package com.mida.bms.report.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.mida.bms.report.common.cons.ReportConst;
import com.mida.bms.report.common.massert.MRAssert;
import com.mida.bms.report.entity.*;
import com.mida.bms.report.enumdata.ReportProcessStatus;
import com.mida.bms.report.enumdata.ReportStatus;
import com.mida.bms.report.enumdata.ReportType;
import com.mida.bms.report.innerdto.ReportIds;
import com.mida.bms.report.mapper.*;
import com.mida.bms.report.service.*;
import com.mida.bms.report.util.WatchUtil;
import com.mida.bms.report.vo.*;
import com.mida.tool.common.result.ActionResult;
import com.mida.tool.common.result.BaseResult;
import com.mida.tool.common.result.ListResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * <h1>报告书写</h1>
 * <p>
 *
 * </p>
 *
 * @author jian.li on 2021/4/28 9:30
 */
@Service
@Transactional
@Slf4j

public class DocReportServiceImpl extends BaseResult implements DocReportService {

    public static final long RESOURCE_INFO_SOID = 18413530021628928L;//应用资源--写报告soid
    public static final long CODING_RULE_INFO_SOID = 27797392413690880L;//报告编码soid


    // ID生成器
    @Autowired
    private SoidService soidService;

    @Autowired
    private SrvDocReportService srvDocReportService;

    @Autowired
    private DocReportPdfService docReportPdfService;

    @Autowired
    private DocCriticalDescMapper docCriticalDescMapper;

    // ---报告部分---
    // 报告危急值
    @Autowired
    private DocReportCriticalValueMapper docReportCriticalValueMapper;

    // 报告生命周期
    @Autowired
    private DocStructReportLifeCycleMapper docStructReportLifeCycleMapper;

    // 结构化报告和检查实例的关系
    @Autowired
    private DocReportRequisitionRelationMapper docReportRequisitionRelationMapper;

    // 报告存储信息
    @Autowired
    private DocStructReportMapper docStructReportMapper;

    // 结构化报告PDF存储
    @Autowired
    private DocStructReportPdfMapper docStructReportPdfMapper;

    // 报告完整存储
    @Autowired
    private DocStructReportJsonMapper docStructReportJsonMapper;

    // 报告存储图片路径
    @Autowired
    private DocStructReportImgMapper docStructReportImgMapper;

    // 业务态报告结构基本信息
    @Autowired
    private DocBusinessStructReportMapper docBusinessStructReportMapper;

    // 业务态报告实例上下文信息
    @Autowired
    private DocBusinessStructIndividualMapper docBusinessStructIndividualMapper;

    // 报告结构实例slot值信息
    @Autowired
    private DocBusinessStructSlotMapper docBusinessStructSlotMapper;

    // 报告存储扩展文字
    @Autowired
    private DocReportClobContentMapper docReportClobContentMapper;


    @Autowired
    private DocCustomTextJsonMapper docCustomTextJsonMapper;

    @Autowired
    private DocCustomTextImgMapper docCustomTextImgMapper;

    // 模板存储扩展文字
    @Autowired
    private DocStructTemplateClobContentMapper docStructTemplateClobContentMapper;

    //模本基本信息
    @Autowired
    private DocStructTemplateInfoService docStructTemplateInfoService;


    /**
     * 模版基本信息的Dao
     */
    @Autowired
    private DocStructTemplateInfoMapper docStructTemplateInfoMapper;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    Map<String, String> mapCss;


    // FIXME: yutao 2021/8/8 必须优化

    /**
     * 暂存报告
     *
     * @param request 暂存报告请求参数
     * @return
     */
    @Override
    public ListResult<ReportResult> saveTemporarily(DocReportPreservationRequest request) {
        log.info("开始暂存报告");

        Map<String, StopWatch> watchMap = WatchUtil.createWatchs("暂存保存报告", "saveReport", "报告图片存储");
        WatchUtil.startAll(watchMap);
        ListResult listResult = new ListResult();

        try {
            ReportIds reportIds = initReportIds(request);

//            //报告存储信息标识
            Long stReportSoid;
            // 删除历史报告
            // 根据申请单标识,登记单标识,检查单标识查询
//            DocReportRequisitionRelationVo docReportRequisitionRelationVo = docReportRequisitionRelationMapper.selectAccurateReport(request.getRequestSoid(), request.getRegistrationFormSoid(), request.getExaminationVisitSoid());
            if (ObjectUtils.isNotEmpty(request.getStReportSoid())) {
                stReportSoid = request.getStReportSoid();
                saveReportNotFirst(request, reportIds, stReportSoid);
            } else {
                stReportSoid = soidService.getSoid();
                saveReportFirst(request, reportIds, stReportSoid);
            }
            WatchUtil.stopAndLog(log, watchMap, "saveReport");

            // 报告图片存储
//            List<DocStructReportImgVo> imgList = request.getDocReportVo().getDocStructReportImgVoList();
            List<DocReportVo> docReportVoList = request.getDocReportVoList();
            saveReportPic(reportIds.getEmployeeSoid(), stReportSoid, docReportVoList);

            ReportResult reportResult = new ReportResult();
            reportResult.setStReportSoid(stReportSoid);
            buildListSuccess(listResult, reportResult);

            WatchUtil.stopAndLog(log, watchMap, "报告图片存储");
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            // FIXME: yutao 2021/8/8 先这样返回也可以，但为了统一代码风格，最好也能同样用MRAssert
            log.error("暂存报告发送异常", e);
            buildListWarn(listResult, "暂存报告失败");
        } finally {
            // FIXME: yutao 2021/8/8 最好不要在 finally 里打印耗时，这样，同样的耗时少了个尾巴时，可以用ELK等工具发现。就能直接知道运行发生了异常
            WatchUtil.stopAndLog(log, watchMap, "暂存保存报告");
            WatchUtil.stopAll(watchMap);
        }
        return listResult;
    }

    private void saveReportFirst(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid) {
        // TODO 后面要加上限制
//            if (ObjectUtils.isEmpty(request.getExaminationVisitSoid())) {
//                buildBadRequestListWarn(listResult, "检查标识不能为空");
//                return listResult;
//            }
        // 新增报告存储信息
        DocStructReport report = new DocStructReport();

        report.setStReportSoid(stReportSoid);
        // 报告流转状态
        report.setReportProcessStatus(request.getReportProcessStatus());
        report.setStEditCount(0);
        // 报告自身状态
        fillReportSelfStatus(request, reportIds, report);
        copyReportIds(reportIds, report);

        // 国标
        soidService.insertOid(stReportSoid, 4);

        // 新增报告完整存储信息
        DocStructReportJson reportJson = fillDocStructReportJson(request, reportIds, stReportSoid);
        docStructReportJsonMapper.insert(reportJson);


        // 按申请单写报告
        if (ReportType.WRITE_REPORT_REQUEST.code.longValue() == request.getReportType()) {
            writeReportByRequest(request, reportIds, stReportSoid);
            // 按登记号或上机号写报告
        } else if (ReportType.WRITE_REPORT_REGISTRATIONNO.code.longValue() == request.getReportType() ||
                ReportType.WRITE_REPORT_EXAMINATIONVISITSOID.code.longValue() == request.getReportType()) {
            //若docReportListVos不为空则为合单情况，为空且instanceVoList不为空则为未合单情况
            List<DocReportListVo> docReportListVos = request.getDocReportListVos();
            List<ServiceInstanceVo> instanceVoList = request.getServiceInstanceVoList();
            if (CollectionUtils.isNotEmpty(docReportListVos)) {
                writeReportCombine(request, reportIds, stReportSoid, docReportListVos);
            } else if (CollectionUtils.isNotEmpty(instanceVoList)) {
                writeReportNotCombine(request, reportIds, stReportSoid, instanceVoList);
            }
        }

        // 新增报告生命周期信息
        Long lifeCycleSoid = saveReportLifeCycle(request, reportIds.getEmployeeSoid(), stReportSoid, 1L);
        // 报告存储信息设置最新生命周期soid
        report.setStReportLifeCycleSoid(lifeCycleSoid);
        srvDocReportService.insertStructReport(report);
    }

    private void writeReportNotCombine(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid, List<ServiceInstanceVo> instanceVoList) {
        int s = 0;
        int size = instanceVoList.size();
        //获取指定数量的soid
        List<Long> soids = soidService.getSoids(size);
        //登记标识
        Long registrationFormSoid = request.getRegistrationFormSoid();
        //登记号
        reportIds.setRegistrationNo(request.getRegistrationNo());
        //申请单标识
        Long requestSoid = request.getRequestSoid();
        //检查标识
        Long operatorSoid = request.getOperatorSoid();
        for (ServiceInstanceVo serviceInstanceVo : instanceVoList) {
            Long relationSoid = soids.get(s++);
            // 新增报告和检查实例的关系
            DocReportRequisitionRelation relation = createDocReportRequisitionRelation(request, reportIds.getEmployeeSoid(), stReportSoid,
                    registrationFormSoid, reportIds.getRegistrationNo(), request.getRequestSoid(), operatorSoid,
                    serviceInstanceVo, relationSoid);
            docReportRequisitionRelationMapper.insert(relation);
        }
        //批量插入oid
        soidService.insertOids(soids, 4);
    }

    private void writeReportCombine(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid, List<DocReportListVo> docReportListVos) {
        for (DocReportListVo docReportListVo : docReportListVos) {
            List<ServiceInstanceVo> serviceInstanceVoList = docReportListVo.getServiceInstanceVoList();
            //登记标识
            Long registrationFormSoid = docReportListVo.getRegistrationFormSoid();
            //登记号
            reportIds.setRegistrationNo(docReportListVo.getRegistrationNo());
            //申请单标识
            Long requestSoid = docReportListVo.getRequestSoid();
            //检查标识
            Long operatorSoid = docReportListVo.getOperatorSoid();
            if (CollectionUtils.isNotEmpty(serviceInstanceVoList)) {
                int s = 0;
                int size = serviceInstanceVoList.size();
                //获取指定数量的soid
                List<Long> soids = soidService.getSoids(size);
                for (ServiceInstanceVo serviceInstanceVo : serviceInstanceVoList) {
                    Long relationSoid = soids.get(s++);
                    // 新增报告和检查实例的关系
                    DocReportRequisitionRelation relation = createDocReportRequisitionRelation(request, reportIds.getEmployeeSoid(),
                            stReportSoid, registrationFormSoid, request.getRegistrationNo(), request.getRequestSoid(),
                            operatorSoid, serviceInstanceVo, relationSoid);
                    docReportRequisitionRelationMapper.insert(relation);
                }
                //批量插入oid
                soidService.insertOids(soids, 4);
            }
        }
    }

    private void writeReportByRequest(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid) {
        if (CollectionUtils.isNotEmpty(request.getMsdServiceInstanceSoidList())) {
            int s = 0;
            int size = request.getMsdServiceInstanceSoidList().size();
            //获取指定数量的soid
            List<Long> soids = soidService.getSoids(size);
            for (int i = 0; i < request.getMsdServiceInstanceSoidList().size(); i++) {
                Long relationSoid = soids.get(s++);
                // 新增报告和检查实例的关系
                DocReportRequisitionRelation relation = createReportRequistrionRelation(request, reportIds, stReportSoid, i, relationSoid);
                docReportRequisitionRelationMapper.insert(relation);


            }
            //批量插入oid
            soidService.insertOids(soids, 4);
        }
    }

    private void saveReportNotFirst(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid) {
        // 删除报告存储图片
        docStructReportImgMapper.deleteByStReportSoid(stReportSoid);

        // 获取生命周期最大序列号
        DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
        Long maxSerialNo = getMaxSerialNo(docStructReport);

        // 更新报告完整存储信息
        updateReportStruct(request, reportIds, stReportSoid);


        DocStructReportLifeCycle lifeCycle =
                docStructReportLifeCycleMapper.selectNewestByStReportSoid(stReportSoid);
        // 非首次保存之前肯定有生命周期记录,故不再判断生命周期记录为空的情况
        if (lifeCycle != null) {
            // 当报告最新生命周期状态为草稿且前后为同一个人写报告时更新生命周期最新记录
            if (lifeCycle.getStatus().longValue() == ReportStatus.DRAFT.code.longValue() && reportIds.getEmployeeSoid().longValue() == lifeCycle.getUpdateUser().longValue()) {
                // 更新生命周期表中对应的报告内容
                lifeCycle.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
                lifeCycle.setUpdateUser(reportIds.getEmployeeSoid());
                docStructReportLifeCycleMapper.updateByPrimaryKey(lifeCycle);
            }
            // 当报告最新生命周期状态为审核退回或前后不是同一个人写报告时新增生命周期记录
            if (lifeCycle.getStatus().longValue() == ReportStatus.REVIEW_RETURNED.code.longValue() || request.getEmployeeSoid().longValue() != lifeCycle.getUpdateUser().longValue()) {
                DocStructReportLifeCycle record = CreateNewDocStructReportLifeCycle(request, reportIds.getEmployeeSoid(), stReportSoid, maxSerialNo);
                docStructReportLifeCycleMapper.insert(record);
                // 设置最新生命周期soid
                docStructReport.setStReportLifeCycleSoid(record.getStReportLifeCycleSoid());
            }
        }

        // 更新报告存储信息
        updateStructReport(request, reportIds, request.getEmployeeSoid(), docStructReport);
        srvDocReportService.updateStructReportSelective(docStructReport);
    }

    // 获取生命周期最大序列号
    public Long getMaxSerialNo(DocStructReport docStructReport) {
        if (ObjectUtils.isNotEmpty(docStructReport)) {
            Long stReportLifeCycleSoid = docStructReport.getStReportLifeCycleSoid();
            if (ObjectUtils.isNotEmpty(stReportLifeCycleSoid)) {
                DocStructReportLifeCycle docStructReportLifeCycle = docStructReportLifeCycleMapper.selectByPrimaryKey(stReportLifeCycleSoid);
                return docStructReportLifeCycle.getSerialNo();
            }
        }
        return null;
    }

    private DocReportRequisitionRelation createReportRequistrionRelation(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid, int i, Long relationSoid) {
        DocReportRequisitionRelation relation = new DocReportRequisitionRelation();
        relation.setStReportSvcSoid(relationSoid);
        relation.setStReportSoid(stReportSoid);
        relation.setRequestSoid(request.getRequestSoid());
        relation.setRegistrationFormSoid(request.getRegistrationFormSoid());
        relation.setRegistrationNo(request.getRegistrationNo());
        relation.setOperatorSoid(request.getOperatorSoid());
        // 服务实例
        relation.setMsdServiceInstanceSoid(Long.valueOf(request.getMsdServiceInstanceSoidList().get(i)));
        relation.setIsDelete(0L);
        relation.setCreateDate(new Date());
        relation.setUpdateDate(new Date());
        relation.setUpdateUser(reportIds.getEmployeeSoid());
        relation.setExamType(request.getExamType());
        return relation;
    }


    private DocStructReportJson fillDocStructReportJson(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid) {
        DocStructReportJson reportJson = new DocStructReportJson();
        Long reportJsonSoid = soidService.getSoid();
        // 结构化报告完整存储标识
        reportJson.setStReportJsonSoid(reportJsonSoid);
        // 结构化模板基本信息标识
        reportJson.setStTemplateInfoSoid(request.getStTemplateInfoSoid());
        // 报告内容存储
        reportJson.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
        // 报告存储信息标识
        reportJson.setStReportSoid(stReportSoid);
        reportJson.setCreateDate(new Date());
        reportJson.setUpdateDate(new Date());
        reportJson.setUpdateUser(reportIds.getEmployeeSoid());
        reportJson.setIsDelete(0L);
        return reportJson;
    }

    private void fillReportSelfStatus(DocReportPreservationRequest request, ReportIds reportIds, DocStructReport report) {
        report.setStatus(request.getReportStatus());
        report.setIsDelete(0L);
        report.setCreateDate(new Date());
        report.setUpdateDate(new Date());
        report.setUpdateUser(reportIds.getEmployeeSoid());
        report.setFirstWriteDoctor(reportIds.getEmployeeSoid());
    }

    private void updateReportStruct(DocReportPreservationRequest request, ReportIds reportIds, Long stReportSoid) {
        DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
        if (ObjectUtils.isNotEmpty(request.getDocReportVoList())) {
            reportJson.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
            reportJson.setUpdateDate(new Date());
            reportJson.setUpdateUser(reportIds.getEmployeeSoid());
            docStructReportJsonMapper.updateByPrimaryKey(reportJson);
        }
    }


    private DocStructReportLifeCycle CreateNewDocStructReportLifeCycle(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid, Long serialNo) {
        DocStructReportLifeCycle record = new DocStructReportLifeCycle();
        record.setStReportSoid(stReportSoid);
        record.setReportProcessStatus(request.getReportProcessStatus());
        record.setStatus(request.getReportStatus());
        record.setIsDelete(0L);
        record.setUpdateDate(new Date());
        record.setCreateDate(new Date());
        record.setUpdateUser(employeeSoid);
        record.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
        record.setStReportLifeCycleSoid(soidService.getSoid());
        if (ObjectUtils.isNotEmpty(serialNo)) {
            record.setSerialNo(serialNo + 1);
        }
        return record;
    }

    private DocStructReport updateStructReport(DocReportPreservationRequest request, ReportIds reportIds, Long employeeSoid, DocStructReport docStructReport) {
        MRAssert.massertNotEmpty(docStructReport, ReportConst.ReportErr.NotExist.REPORT);

        // 报告修改次数加一
        docStructReport.setStEditCount(docStructReport.getStEditCount() + 1);
        docStructReport.setUpdateDate(new Date());
        // 报告自身状态
        docStructReport.setStatus(request.getReportStatus());
        // 报告流转状态
        docStructReport.setReportProcessStatus(request.getReportProcessStatus());
        docStructReport.setUpdateUser(employeeSoid);
        copyReportIds(reportIds, docStructReport);
        return docStructReport;
    }

    private void copyReportIds(ReportIds reportIds, DocStructReport docStructReport) {
        if (StringUtils.isNotEmpty(reportIds.getCustomerSoid())) {
            docStructReport.setCustomerSoid(Long.valueOf(reportIds.getCustomerSoid()));
        }
        if (StringUtils.isNotEmpty(reportIds.getApntPersonSoid())) {
            docStructReport.setApntPersonSoid(Long.valueOf(reportIds.getApntPersonSoid()));
        }
        if (StringUtils.isNotEmpty(reportIds.getPatientSoid())) {
            docStructReport.setPatientSoid(Long.valueOf(reportIds.getPatientSoid()));
        }
    }


    private ReportIds initReportIds(DocReportPreservationRequest request) {
        ReportIds reportIds = new ReportIds();
        Map<String, String> patientInfoMap = request.getPatientInfoMap();
        if (MapUtils.isNotEmpty(patientInfoMap)) {
            // 角色标识
            reportIds.setCustomerSoid(patientInfoMap.get("customerSoid"));
            // 患者信息标识(From our system)
            reportIds.setApntPersonSoid(patientInfoMap.get("apntPersonSoid"));
            // 病人标识(From HIS)
            reportIds.setPatientSoid(patientInfoMap.get("patientSoid"));
            // 提交科室标识
            reportIds.setSubmitDeptSoid(patientInfoMap.get("submitDeptSoid"));
        }
        reportIds.setEmployeeSoid(request.getEmployeeSoid());
        return reportIds;
    }

    /**
     * @param request
     * @param employeeSoid
     * @param stReportSoid
     * @param serialNo     生命周期序列号
     * @return
     */
    private Long saveReportLifeCycle(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid, Long serialNo) {
        DocStructReportLifeCycle lifeCycle = new DocStructReportLifeCycle();
        Long lifeCycleSoid = soidService.getSoid();
        lifeCycle.setStReportLifeCycleSoid(lifeCycleSoid);
        lifeCycle.setStReportSoid(stReportSoid);

        // 报告流转状态
        lifeCycle.setReportProcessStatus(request.getReportProcessStatus());

        // 报告自身状态
        lifeCycle.setStatus(request.getReportStatus());
        lifeCycle.setCreateDate(new Date());
        lifeCycle.setUpdateDate(new Date());
        lifeCycle.setUpdateUser(employeeSoid);
        lifeCycle.setIsDelete(0L);

        // 报告更新内容
        lifeCycle.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
        // 生命周期序列号
        lifeCycle.setSerialNo(serialNo);
        docStructReportLifeCycleMapper.insert(lifeCycle);

        // 国标
        soidService.insertOid(lifeCycleSoid, 4);
        return lifeCycleSoid;
    }

    private void saveReportPic(Long employeeSoid, Long stReportSoid, List<DocReportVo> docReportVoList) {
        if (ObjectUtils.isNotEmpty(docReportVoList)) {
            for (DocReportVo docReportVo : docReportVoList) {
                List<DocStructReportImgVo> imgList = docReportVo.getDocStructReportImgVoList();
                if (CollectionUtils.isNotEmpty(imgList)) {
                    for (int i = 0; i < imgList.size(); i++) {
                        DocStructReportImgVo img = imgList.get(i);
                        DocStructReportImg target = new DocStructReportImg();
                        BeanUtils.copyProperties(img, target);
                        Long imgSoid = soidService.getSoid();
                        target.setStReportImgSoid(imgSoid);
                        target.setCreateDate(new Date());
                        target.setUpdateDate(new Date());
                        target.setIsDelete(0L);
                        target.setUpdateUser(employeeSoid);
                        target.setStReportSoid(stReportSoid);
                        target.setUpdateUser(employeeSoid);
                        docStructReportImgMapper.insert(target);

                        // 国标
                        soidService.insertOid(imgSoid, 4);
                    }
                }
            }
        }
    }

    /**
     * 输入值check 可以改成给控制成调用
     *
     * @param request
     * @return
     */
    @Override
    public void requestCheck(DocReportPreservationRequest request) {
        log.info("开始暂存报告请求参数check");
        StopWatch stopWatch = StopWatch.createStarted();

        MRAssert.massertNotEmpty(request.getEmployeeSoid(), ReportConst.ReportErr.Empty.USER_INFO);
        MRAssert.massertNotEmpty(request.getRequestSoid(), ReportConst.ReportErr.Empty.REQUEST_ID);
        MRAssert.massertNotEmpty(request.getPersonSoid(), ReportConst.ReportErr.Empty.PATIENT_SOID);
        MRAssert.massertNotEmpty(request.getStTemplateInfoSoid(), ReportConst.ReportErr.Empty.TEMPLATE);

        Long reportType = request.getReportType();
        MRAssert.massertNotEmpty(reportType, ReportConst.ReportErr.Empty.REPORT_TYPE);
        MRAssert.massertIn(ReportConst.ReportErr.Type.REPORT, reportType, ReportType.WRITE_REPORT_EXAMINATIONVISITSOID.code,
                ReportType.WRITE_REPORT_REGISTRATIONNO.code, ReportType.WRITE_REPORT_REQUEST.code);

        if (ReportType.WRITE_REPORT_REQUEST.code.equals(reportType)) {
            MRAssert.massertNotEmpty(request.getMsdServiceInstanceSoidList(), ReportConst.ReportErr.Empty.SERVICE);
        }

        stopWatch.stop();
        log.info("本次暂存保存报告check耗时: " + stopWatch.getTime() + "ms");
    }

    // FIXME: yutao 2021/8/8 优化

    /**
     * 签署报告
     * <p>
     * 共保存三份:
     * 1.json
     * 2.pdf
     * 3.结构化报告
     *
     * @param request 保存报告请求参数
     * @return
     */
    @Override
    public ListResult<String> saveDocReport(DocReportPreservationRequest request) {
        log.info("开始保存报告");
        StopWatch stopWatch = StopWatch.createStarted();

        ListResult listResult = new ListResult();

        Map<String, StopWatch> watchMap = WatchUtil.createWatchs("check", "save", "saveImg");
        WatchUtil.startAll(watchMap);
        try {

            reportCheck4SaveDocReport(request);

            WatchUtil.stopAndLog(log, watchMap, "check");

            DocStructReport docStructReport = null;
            if (ObjectUtils.isNotEmpty(request.getStReportSoid())) {
                docStructReport = docStructReportMapper.selectByPrimaryKey(request.getStReportSoid());
                MRAssert.massertNotEmpty(docStructReport, ReportConst.ReportErr.NotExist.REPORT);
            }

            ReportIds reportIds = new ReportIds();
            reportIds.setEmployeeSoid(request.getEmployeeSoid());

            String registrationNo = null;
            Map<String, String> patientInfoMap = request.getPatientInfoMap();
            if (MapUtils.isNotEmpty(patientInfoMap)) {
                // 角色标识
                reportIds.setCustomerSoid(patientInfoMap.get("customerSoid"));
                // 患者信息标识(From our system)
                reportIds.setApntPersonSoid(patientInfoMap.get("apntPersonSoid"));
                // 病人标识(From HIS)
                reportIds.setPatientSoid(patientInfoMap.get("patientSoid"));
            }

            //报告存储信息标识
            Long stReportSoid = null;

            if (ObjectUtils.isNotEmpty(request.getStReportSoid())) {// 非首次签署报告
                stReportSoid = saveNoFirst(request, docStructReport, reportIds);
            } else {// 首次签署报告

                // TODO 后面要加上限制
//            if (ObjectUtils.isEmpty(request.getExaminationVisitSoid())) {
//                buildBadRequestListWarn(listResult, "检查标识不能为空");
//                return listResult;
//            }
                stReportSoid = saveFirst(request, reportIds);
            }

            WatchUtil.stopAndLog(log, watchMap, "save");

            // 报告图片存储
            saveReportImg(request, stReportSoid, reportIds);

            WatchUtil.stopAndLog(log, watchMap, "saveImg");

            buildListSuccess(listResult, stReportSoid);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("保存报告发送异常", e);
            buildListWarn(listResult, "保存报告失败");
        } finally {
            stopWatch.stop();
            WatchUtil.stopAll(watchMap);
            log.info("本次保存报告耗时: " + stopWatch.getTime() + "ms");
        }
        return listResult;
    }

    private void saveReportImg(DocReportPreservationRequest request, Long stReportSoid, ReportIds reportIds) {
        //            List<DocStructReportImgVo> imgList = request.getDocReportVo().getDocStructReportImgVoList();
        List<DocReportVo> docReportVoList = request.getDocReportVoList();
        if (ObjectUtils.isNotEmpty(docReportVoList)) {
            for (DocReportVo docReportVo : docReportVoList) {
                List<DocStructReportImgVo> imgList = docReportVo.getDocStructReportImgVoList();
                if (CollectionUtils.isEmpty(imgList)) {
                    continue;
                }
                for (int i = 0; i < imgList.size(); i++) {
                    DocStructReportImgVo img = imgList.get(i);
                    DocStructReportImg target = new DocStructReportImg();
                    BeanUtils.copyProperties(img, target);
                    Long imgSoid = soidService.getSoid();
                    target.setStReportImgSoid(imgSoid);
                    if (ObjectUtils.isNotEmpty(request.getExaminationVisitSoid())) {
                        // 影像号(检查号)
                        target.setStPatientId(request.getExaminationVisitSoid().toString());
                    }
                    target.setCreateDate(new Date());
                    target.setUpdateDate(new Date());
                    target.setIsDelete(0L);
                    target.setUpdateUser(reportIds.getEmployeeSoid());
                    target.setStReportSoid(stReportSoid);
                    docStructReportImgMapper.insert(target);

                    // 国标
                    soidService.insertOid(imgSoid, 4);
                }

            }
        }
    }

    private void reportCheck4SaveDocReport(DocReportPreservationRequest request) {
        MRAssert.massertNotEmpty(request.getEmployeeSoid(), ReportConst.ReportErr.Empty.USER_INFO);
        MRAssert.massertNotEmpty(request.getRequestSoid(), ReportConst.ReportErr.Empty.REQUEST_ID);
        MRAssert.massertNotEmpty(request.getPersonSoid(), ReportConst.ReportErr.Empty.PATIENT_SOID);
        MRAssert.massertNotEmpty(request.getStTemplateInfoSoid(), ReportConst.ReportErr.Empty.TEMPLATE);
        MRAssert.massertNotEmpty(request.getReportType(), ReportConst.ReportErr.Empty.REPORT_TYPE);

        // 报告类型check
        Long reportType = request.getReportType();
        MRAssert.massertIn(ReportConst.ReportErr.Type.REPORT, reportType, ReportType.WRITE_REPORT_EXAMINATIONVISITSOID.code,
                ReportType.WRITE_REPORT_REGISTRATIONNO.code, ReportType.WRITE_REPORT_REQUEST.code);

        // 按申请单写报告
        if (ReportType.WRITE_REPORT_REQUEST.code.longValue() == reportType) {
            MRAssert.massertNotEmpty(request.getMsdServiceInstanceSoidList(), ReportConst.ReportErr.Empty.SERVICE);
        }
    }

    /**
     * 业务态报告结构基本信息
     *
     * @param docReportVo  报告vo
     * @param stReportSoid 报告存储信息标识
     */
    private void saveStruct(DocReportVo docReportVo, Long stReportSoid) {
        // 业务态报告结构基本信息
        List<DocReportParagraphVo> docStructParagraphVoList = docReportVo.getDocStructParagraphVoList();
        for (DocReportParagraphVo docReportParagraphVo : docStructParagraphVoList) {
            List<DocReportFragmentVo> docReportFragmentVoList = docReportParagraphVo.getDocStructFragmentVoList();
            if (ObjectUtils.isNotEmpty(docReportFragmentVoList)) {
                for (DocReportFragmentVo docReportFragmentVo : docReportFragmentVoList) {
                    //一：处理片段中的实例(纯实例)
                    DisposeIndividualByFragment(stReportSoid, docReportParagraphVo, docReportFragmentVo);
                    //二：处理本体对应的slot和value  、处理slot中实例
                    DisposeNoumenonByFragment(stReportSoid, docReportParagraphVo, docReportFragmentVo);

                }
            }

        }
    }

    /**
     * @return void
     * @Author WXL
     * @Description 处理本体对应的slot和value  、处理slot中实例
     * @Date 2021/8/5
     * @Param [stReportSoid, docReportParagraphVo, docReportFragmentVo]
     **/
    private void DisposeNoumenonByFragment(Long stReportSoid, DocReportParagraphVo docReportParagraphVo, DocReportFragmentVo docReportFragmentVo) {
        //二：处理本体对应的slot和value  、处理slot中实例
        if (docReportFragmentVo.getNoumenonSoid() != null && docReportFragmentVo.getIndividualSoid() == null) {
            //2.1处理本体对应的slot和value
            // 保存报告结构基本信息和实例上下文信息
            Long bnsStructInfoSoid = saveBaseAndIndividual(stReportSoid, docReportParagraphVo,
                    docReportFragmentVo);
            //2.2设置结构实例slot信息，添加到数据库
            List<DocStructTemplateSlotVo> docStructTemplateSlotVoList =
                    docReportFragmentVo.getDocStructTemplateSlotVoList();
            if (ObjectUtils.isNotEmpty(docStructTemplateSlotVoList)) {
                //处理本体slot和value
                //处理slot中本体数据
                this.addNoumenon(docStructTemplateSlotVoList, docReportParagraphVo, docReportFragmentVo, stReportSoid);
                //2.2.1处理slot中实例数据
                Map<Long, List<DocStructTemplateSlotVo>> map = docStructTemplateSlotVoList
                        .stream()
                        .filter(m -> m.getIndividualSoid() != null)
                        .collect(Collectors.groupingBy(DocStructTemplateSlotVo::getIndividualSoid));

                for (List<DocStructTemplateSlotVo> values : map.values()) {
                    DocStructTemplateSlotVo docStructTemplateSlotVo = values.get(0);
                    // 保存报告结构基本信息和实例上下文信息
                    Long structInfoSoid = saveBaseAndIndividual(stReportSoid, docReportParagraphVo, docReportFragmentVo, docStructTemplateSlotVo);
                    List<DocStructTemplateSlotVo> docStructTemplateSlotVoValues =
                            docStructTemplateSlotVoList.stream()
                                    .filter(m -> StringUtils.isNoneEmpty(m.getDocStructSlotValueVo().getDataValue()))
                                    .collect(Collectors.toList());//过滤片段slotvalue为空的情况
                    for (DocStructTemplateSlotVo docStructTemplateSlotVo1 : docStructTemplateSlotVoValues) {
                        saveIndividualSlot(structInfoSoid, docStructTemplateSlotVo1);
                    }

                }
            }
        }
    }

    /**
     * @return java.lang.Long
     * @Author WXL
     * @Description 设置报告结构基本信息, 设置实例上下文信息并保存
     * @Date 2021/8/5
     * @Param [stReportSoid, docReportParagraphVo, docReportFragmentVo, docStructTemplateSlotVo]
     **/
    private Long saveBaseAndIndividual(Long stReportSoid, DocReportParagraphVo docReportParagraphVo, DocReportFragmentVo docReportFragmentVo, DocStructTemplateSlotVo docStructTemplateSlotVo) {
        //2.2.2.设置报告结构基本信息,添加到数据库中
        DocBusinessStructReport docBusinessStructReport = new DocBusinessStructReport();
        docBusinessStructReport.setIndividualSoid(docStructTemplateSlotVo.getIndividualSoid());
        docBusinessStructReport.setIndividualName(docStructTemplateSlotVo.getIndividualName());
        docBusinessStructReport.setNoumenonSoid(docStructTemplateSlotVo.getNoumenonSoid());
        Long structInfoSoid = soidService.getSoid();//业务态报告结构基本信息标识
        docBusinessStructReport.setBnsStructInfoSoid(structInfoSoid);
        docBusinessStructReport.setStReportSoid(stReportSoid);//设置报告存储信息标识
        docBusinessStructReport.setIsDelete(0L);
        docBusinessStructReport.setCreateDate(new Date());
        docBusinessStructReport.setUpdateDate(new Date());
        docBusinessStructReportMapper.insertSelective(docBusinessStructReport);

        //2.2.3.设置实例上下文信息，添加到数据库中
        DocBusinessStructIndividual docBusinessStructIndividual =
                new DocBusinessStructIndividual();
        docBusinessStructIndividual.setStParagraphSoid(docReportParagraphVo.getStParagraphSoid());//设置实例上下文段落标识
        docBusinessStructIndividual.setStFragmentSoid(docReportFragmentVo.getStFragmentSoid());
        docBusinessStructIndividual.setIsDelete(0L);
        docBusinessStructIndividual.setCreateDate(new Date());
        docBusinessStructIndividual.setUpdateDate(new Date());
        docBusinessStructIndividual.setBnsStructInfoSoid(structInfoSoid);//设置报告结构基本信息标识
        docBusinessStructIndividual.setBnsStIndSoid(soidService.getSoid());
        docBusinessStructIndividualMapper.insertSelective(docBusinessStructIndividual);
        return structInfoSoid;
    }

    /**
     * @return void
     * @Author WXL
     * @Description 处理片段中的实例(纯实例)
     * @Date 2021/8/5
     * @Param [stReportSoid, docReportParagraphVo, docReportFragmentVo]
     **/
    private void DisposeIndividualByFragment(Long stReportSoid, DocReportParagraphVo docReportParagraphVo, DocReportFragmentVo docReportFragmentVo) {
        //一：处理片段中的实例(纯实例)
        if (docReportFragmentVo.getNoumenonSoid() != null && docReportFragmentVo.getIndividualSoid() != null) {
            //1.保存报告结构基本信息和实例上下文信息
            Long bnsStructInfoSoid = saveBaseAndIndividual(stReportSoid, docReportParagraphVo,
                    docReportFragmentVo);
            //2.设置结构实例slot信息，添加到数据库
            List<DocStructTemplateSlotVo> docStructTemplateSlotVoList =
                    docReportFragmentVo.getDocStructTemplateSlotVoList();
            if (!org.springframework.util.CollectionUtils.isEmpty(docStructTemplateSlotVoList)) {
                for (DocStructTemplateSlotVo docStructTemplateSlotVo : docStructTemplateSlotVoList) {
                    saveIndividualSlot(bnsStructInfoSoid, docStructTemplateSlotVo);
                }
            }

        }
    }

    /**
     * @param bnsStructInfoSoid       业务态报告结构基本信息标识
     * @param docStructTemplateSlotVo 报告片段slotVo
     * @Description: 设置结构实例slot信息, 保存到数据库中
     * @Date: Created in 13:15 2021/5/25
     */
    private void saveIndividualSlot(Long bnsStructInfoSoid, DocStructTemplateSlotVo docStructTemplateSlotVo) {

        DocBusinessStructSlot docBusinessStructSlot = new DocBusinessStructSlot();
        docBusinessStructSlot.setBnsStSlotSoid(soidService.getSoid());
        docBusinessStructSlot.setBnsStructInfoSoid(bnsStructInfoSoid);//设置报告结构基本信息标识
        docBusinessStructSlot.setSlotSoid(docStructTemplateSlotVo.getSlotSoid());
        docBusinessStructSlot.setDataValue(docStructTemplateSlotVo.getDocStructSlotValueVo().getDataValue());
        docBusinessStructSlot.setSlotCodingSoid(docStructTemplateSlotVo.getDerailCodingSystemSoid());//值标识(编码体系soid)
        docBusinessStructSlot.setCreateDate(new Date());
        docBusinessStructSlot.setIsDelete(0l);
        docBusinessStructSlotMapper.insertSelective(docBusinessStructSlot);
    }

    /**
     * @param stReportSoid         报告存储信息标识
     * @param docReportParagraphVo 报告段落vo
     * @param docReportFragmentVo  报告片段vo
     * @Description: 设置报告结构基本信息, 设置实例上下文信息并保存
     * @Date: Created in 11:58 2021/5/25
     */
    private Long saveBaseAndIndividual(Long stReportSoid, DocReportParagraphVo docReportParagraphVo,
                                       DocReportFragmentVo docReportFragmentVo) {
        //1.设置报告结构基本信息,添加到数据库中
        DocBusinessStructReport docBusinessStructReport = new DocBusinessStructReport();
        docBusinessStructReport.setIndividualSoid(docReportFragmentVo.getIndividualSoid());
        docBusinessStructReport.setIndividualName(docReportFragmentVo.getIndividualName());
        docBusinessStructReport.setNoumenonSoid(docReportFragmentVo.getNoumenonSoid());
        Long bnsStructInfoSoid = soidService.getSoid();//业务态报告结构基本信息标识
        docBusinessStructReport.setBnsStructInfoSoid(bnsStructInfoSoid);
        docBusinessStructReport.setStReportSoid(stReportSoid);//设置报告存储信息标识
        docBusinessStructReport.setIsDelete(0l);
        docBusinessStructReport.setCreateDate(new Date());
        docBusinessStructReportMapper.insertSelective(docBusinessStructReport);

        //2.设置实例上下文信息，添加到数据库中
        DocBusinessStructIndividual docBusinessStructIndividual = new DocBusinessStructIndividual();
        docBusinessStructIndividual.setStParagraphSoid(docReportParagraphVo.getStParagraphSoid());//设置实例上下文段落标识
        docBusinessStructIndividual.setStFragmentSoid(docReportFragmentVo.getStFragmentSoid());
        docBusinessStructIndividual.setIsDelete(0L);
        docBusinessStructIndividual.setCreateDate(new Date());
        docBusinessStructIndividual.setBnsStructInfoSoid(bnsStructInfoSoid);//设置报告结构基本信息标识
        docBusinessStructIndividual.setBnsStIndSoid(soidService.getSoid());
        docBusinessStructIndividualMapper.insertSelective(docBusinessStructIndividual);
        return bnsStructInfoSoid;
    }

    /**
     * 为报告生成内容的soid
     *
     * @param docReportVo 报告
     * @return
     */
    private DocReportVo generateSoidForReport(DocReportVo docReportVo) {
        if (ObjectUtils.isNotEmpty(docReportVo)) {
            // 处理段落
            if (CollectionUtils.isNotEmpty(docReportVo.getDocStructParagraphVoList())) {
                List<DocReportParagraphVo> docStructParagraphVoList = docReportVo.getDocStructParagraphVoList();
                for (int i = 0; i < docStructParagraphVoList.size(); i++) {
                    DocReportParagraphVo paragraph = docStructParagraphVoList.get(i);
//                    Long stParagraphSoid = cmoidGanerator.getSOID();
                    Long stParagraphSoid = soidService.getSoid();
                    // 结构化模板段落标识
                    paragraph.setStParagraphSoid(stParagraphSoid);

                    // 处理段落slot
                    if (CollectionUtils.isNotEmpty(paragraph.getDocParagraphSlotVoList())) {
                        List<DocStructTemplateSlotVo> docParagraphSlotVoList = paragraph.getDocParagraphSlotVoList();
                        for (int i1 = 0; i1 < docParagraphSlotVoList.size(); i1++) {
                            DocStructTemplateSlotVo paragraphSlot = docParagraphSlotVoList.get(i1);
//                            Long stTemplateSlotSoid = cmoidGanerator.getSOID();
                            Long stTemplateSlotSoid = soidService.getSoid();
                            // 结构化报告扩展属性标识
                            paragraphSlot.setStTemplateSlotSoid(stTemplateSlotSoid);
                            // 结构化报告模板段落片段标识
                            paragraphSlot.setStFragraSoid(stParagraphSoid);

                            // 处理段落slot value
                            if (ObjectUtils.isNotEmpty(paragraphSlot.getDocStructSlotValueVo())) {
                                DocStructSlotValueVo slotvalue = paragraphSlot.getDocStructSlotValueVo();
                                slotvalue.setStTempleSlotSoid(stTemplateSlotSoid);
//                                slotvalue.setStSlotValueSoid(cmoidGanerator.getSOID());
                                slotvalue.setStSlotValueSoid(soidService.getSoid());
                            }
                        }
                    }

                    // 处理片段
                    if (CollectionUtils.isNotEmpty(paragraph.getDocStructFragmentVoList())) {
                        List<DocReportFragmentVo> docStructFragmentVoList = paragraph.getDocStructFragmentVoList();
                        for (int i2 = 0; i2 < docStructFragmentVoList.size(); i2++) {
                            DocReportFragmentVo fragment = docStructFragmentVoList.get(i2);
//                            Long stFragmentSoid = cmoidGanerator.getSOID();
                            Long stFragmentSoid = soidService.getSoid();
                            // 结构化模板片段标识
                            fragment.setStFragmentSoid(stFragmentSoid);
                            // 结构化模板段落标识
                            fragment.setStParagraphSoid(stParagraphSoid);

                            // 处理片段slot
                            if (CollectionUtils.isNotEmpty(fragment.getDocStructTemplateSlotVoList())) {
                                List<DocStructTemplateSlotVo> fragmentSlotList =
                                        fragment.getDocStructTemplateSlotVoList();
                                for (int i3 = 0; i3 < fragmentSlotList.size(); i3++) {
                                    DocStructTemplateSlotVo fragmentSlot = fragmentSlotList.get(i3);
//                                    Long stTemplateSlotSoid = cmoidGanerator.getSOID();
                                    Long stTemplateSlotSoid = soidService.getSoid();
                                    fragmentSlot.setStTemplateSlotSoid(stTemplateSlotSoid);
                                    fragmentSlot.setStFragraSoid(stFragmentSoid);

                                    // 处理片段slot value
                                    if (ObjectUtils.isNotEmpty(fragmentSlot.getDocStructSlotValueVo())) {
                                        DocStructSlotValueVo slotValue = fragmentSlot.getDocStructSlotValueVo();
                                        slotValue.setStTempleSlotSoid(stTemplateSlotSoid);
//                                        slotValue.setStSlotValueSoid(cmoidGanerator.getSOID());
                                        slotValue.setStSlotValueSoid(soidService.getSoid());
                                    }
                                }
                            }
                        }
                    }

                }
            }
        }
        return docReportVo;
    }

    /**
     * 报告(初写完成待审核)编辑/撤回
     *
     * @param stReportSoid 报告存储信息标识
     * @return
     */
    @Override
    public ActionResult editDocReport(Long stReportSoid, Long employeeSoid) {
        log.info("开始报告编辑/撤回,条件:" + stReportSoid);
        StopWatch stopWatch = StopWatch.createStarted();
        ActionResult actionResult = new ActionResult();

        reportCheck4SaveDocReport(stReportSoid, employeeSoid);

        try {
            DocStructReport report = docStructReportMapper.selectByPrimaryKey(stReportSoid);
            // 报告和检查实例关系
            if (ObjectUtils.isNotEmpty(report)) {
                // 报告存储信息
                // 判断报告流转状态是否为初写完成待审核
                if (report.getReportProcessStatus().longValue() == ReportProcessStatus.TO_BE_REVIEWED.code.longValue()) {
                    // 1. 更新报告存储信息报告自身状态,报告流转状态
                    // 报告流转状态置为待书写
                    report.setReportProcessStatus(ReportProcessStatus.TO_BE_WRITTEN.code);
                    // 报告自身状态置为草稿
                    report.setStatus(ReportStatus.DRAFT.code);
                    report.setUpdateDate(new Date());

                    // 2. 新增生命周期数据
                    // 查询最新的报告生命周期记录
                    Long maxSerialNo = getMaxSerialNo(report);
                    DocStructReportLifeCycle lifeCycle =
                            docStructReportLifeCycleMapper.selectNewestByStReportSoid(report.getStReportSoid());
                    DocStructReportLifeCycle newlifeCycle = new DocStructReportLifeCycle();
                    Long soid = soidService.getSoid();
                    lifeCycle.setStReportLifeCycleSoid(soid);
                    lifeCycle.setReportContent(lifeCycle.getReportContent());
                    lifeCycle.setUpdateUser(employeeSoid);
                    lifeCycle.setCreateDate(new Date());
                    lifeCycle.setUpdateDate(new Date());
                    if (ObjectUtils.isNotEmpty(maxSerialNo)) {
                        lifeCycle.setSerialNo(maxSerialNo + 1);
                    }
                    lifeCycle.setIsDelete(0L);
                    lifeCycle.setStReportSoid(report.getStReportSoid());
                    // 报告自身状态置为草稿
                    lifeCycle.setStatus(ReportStatus.DRAFT.code);
                    // 报告流转状态置为待书写
                    lifeCycle.setReportProcessStatus(ReportProcessStatus.TO_BE_WRITTEN.code);
                    docStructReportLifeCycleMapper.insert(lifeCycle);

                    report.setStReportLifeCycleSoid(soid);
                    srvDocReportService.updateStructReport(report);
                }

            }
            buildActionSuccess(actionResult);
        } catch (Exception e) {
            log.error("报告编辑/撤回发送异常", e);
            buildActionWarn(actionResult, "报告编辑/撤回失败");
        } finally {
            stopWatch.stop();
            log.info("本次报告编辑/撤回耗时: " + stopWatch.getTime() + "ms");
        }

        return actionResult;
    }

    public void reportCheck4SaveDocReport(Long stReportSoid, Long employeeSoid) {
        log.info("开始报告编辑/撤回请求参数check");
        StopWatch stopWatch = StopWatch.createStarted();

        MRAssert.massertNotEmpty(stReportSoid, ReportConst.ReportErr.Empty.REPORT_ID);
        MRAssert.massertNotEmpty(employeeSoid, ReportConst.ReportErr.Empty.USER_INFO);

        stopWatch.stop();
        log.info("本次报告编辑/撤回请求参数check耗时: " + stopWatch.getTime() + "ms");
    }

    // FIXME: yutao 2021/8/8 尽量优化

    /**
     * 报告回显
     *
     * @param request 报告回显请求参数
     * @return
     */
    @Override
    public ListResult<ReportResult> getDocReport(DocReportInitializationRequest request) {
        log.info("开始报告回显,回显条件: " + request);
        StopWatch stopWatch = StopWatch.createStarted();
        ListResult<ReportResult> result = new ListResult<>();
        if (ObjectUtils.isEmpty(request.getRequestSoid())) {
            log.error("申请单标识不能为空");
            buildBadRequestListWarn(result, "申请单标识不能为空");
            return result;
        }
        // TODO 后面要加上限制
//        if (ObjectUtils.isEmpty(request.getExaminationVisitSoid())) {
//            log.error("检查标识不能为空");
//            buildBadRequestListWarn(result, "检查标识不能为空");
//            return result;
//        }

        try {
            DocReportRequisitionRelationVo docReportRequisitionRelationVo = docReportRequisitionRelationMapper.selectAccurateReport(request.getRequestSoid(),
                    StringUtils.isNotEmpty(request.getRegistrationFormSoid()) ? Long.valueOf(request.getRegistrationFormSoid()) : null,
                    StringUtils.isNotEmpty(request.getExaminationVisitSoid()) ? Long.valueOf(request.getExaminationVisitSoid()) : null);
            if (ObjectUtils.isNotEmpty(docReportRequisitionRelationVo)) {
                // 报告存储信息标识
                Long stReportSoid = docReportRequisitionRelationVo.getStReportSoid();
                if (stReportSoid != null) {
                    // 报告存储信息
                    DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
                    // 报告完整存储(json)
                    DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
                    if (reportJson != null) {
                        // 报告流转状态
                        String reportProcessStatus = null;
                        // 报告危急值标识
                        Long reportCriticalValueSoid = null;
                        Long reportStatus = null;
                        if (docStructReport != null) {
                            Long processStatus = docStructReport.getReportProcessStatus();
                            reportStatus = docStructReport.getStatus();
                            if (processStatus != null) {
                                if (processStatus.longValue() == ReportProcessStatus.TO_BE_WRITTEN.code) {
                                    // 待书写
                                    reportProcessStatus = ReportProcessStatus.TO_BE_WRITTEN.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.PRINT_COMPLETED.code) {
                                    // 打印完成
                                    reportProcessStatus = ReportProcessStatus.PRINT_COMPLETED.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.REVIEW_COMPLETED.code) {
                                    // 审核完成
                                    reportProcessStatus = ReportProcessStatus.REVIEW_COMPLETED.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.TO_BE_REVIEWED.code) {
                                    // 初写完成待审核
                                    reportProcessStatus = ReportProcessStatus.TO_BE_REVIEWED.name;
                                }
                            }

                            reportCriticalValueSoid = docStructReport.getReportCriticalValueSoid();
                        }
                        String reportContent = reportJson.getReportContent();
                        Long stTemplateInfoSoid = reportJson.getStTemplateInfoSoid();
                        if (StringUtils.isNotEmpty(reportContent) && stTemplateInfoSoid != null) {
                            // 报告
//                            DocReportVo docReportVo = JSONObject.parseObject(reportContent, DocReportVo.class);
                            List<DocReportVo> docReportVoList = JSONObject.parseArray(reportContent, DocReportVo.class);
                            ReportResult report = new ReportResult();
                            // 报告模板soid
                            report.setStTemplateInfoSoid(stTemplateInfoSoid);
                            // 报告
                            report.setDocReportVoList(docReportVoList);
                            // 报告流转状态
                            report.setReportProcessStatus(reportProcessStatus);
                            // 报告存储信息soid
                            report.setStReportSoid(stReportSoid);
                            // 报告自身状态
                            if (ObjectUtils.isNotEmpty(reportStatus)) {
                                report.setReportStatus(reportStatus.toString());
                            }
                            // 报告加急状态
                            report.setEmergencySign(request.getEmergencySign());
                            // 报告危急值状态
                            report.setReportCriticalValueSoid(reportCriticalValueSoid);

                            // 添加特殊段落模块信息
                            List<DocReportClobContent> docReportClobContents =
                                    docReportClobContentMapper.selectByStReportSoid(stReportSoid);
                            report.setDocReportClobContentList(docReportClobContents);

                            buildListSuccess(result, report);
                        }
                    }
                }
            }

        } catch (Exception e) {
            log.error("报告回显发送异常", e);
            buildListWarn(result, "报告回显失败");
        } finally {
            stopWatch.stop();
            log.info("本次报告回显耗时: " + stopWatch.getTime() + "ms");
        }
        return result;
    }

    /**
     * 业务态保存报告模板
     *
     * @param request 报告模板vo
     * @return
     */
    @Override
    public ActionResult saveTemplate(DocReportPreservationRequest request) {
        log.info("开始保存报告模板");
        StopWatch stopWatch = StopWatch.createStarted();
        ActionResult result = new ActionResult();

//        FTPUtil ftpUtil = new FTPUtil();
//        // 获取FTPClient对象
//        FTPClient ftpClient = ftpUtil.getFTPClient(ftpHost, ftpPort, ftpUserName, ftpPassword);
//        FileOutputStream fileOutputStream = null;
//        FileInputStream fileInputStream = null;
//        // 临时图片
//        File tempImg = null;

        try {
            //校验参数合法性
            List<DocReportVo> docReportVoList = request.getDocReportVoList();

            if (CollectionUtils.isEmpty(docReportVoList)) {
                result.setStatus(HttpStatus.BAD_REQUEST.value());
                result.setMessage("模板报告数据不能为空");
                return result;
            }

            if (ObjectUtils.isNotEmpty(docReportVoList)) {
                for (DocReportVo docReportVo : docReportVoList) {
                    // 模板不保存图片
                    docReportVo.setDocStructReportImgVoList(null);
                }
            }


            if (request.getDocReportVoList().get(0).getStTemplateInfoSoid() == null) {
                log.error("原模板基本信息soid不能为空");
                buildBadRequestActionWarn(result, "原模板基本信息soid不能为空");
                return result;
            }
            //1.添加模板基本信息
            DocStructTemplateInfo data = new DocStructTemplateInfo();
            Long stTemplateInfoSoid1 = request.getDocReportVoList().get(0).getStTemplateInfoSoid();
            if (ObjectUtils.isNotEmpty(stTemplateInfoSoid1)) {
                //获取模板
                ListResult docStructTemplateInfo =
                        docStructTemplateInfoService.getDocStructTemplateInfo(request.getDocReportVoList().get(0).getStTemplateInfoSoid());
                data = (DocStructTemplateInfo) docStructTemplateInfo.getData();
            }
            if (data == null) {
                log.error("原模板不存在");
                buildBadRequestActionWarn(result, "原模板不存在");
                return result;
            }
            DocStructTemplateInfoVo docStructTemplateInfoVo = new DocStructTemplateInfoVo();
            BeanUtils.copyProperties(data, docStructTemplateInfoVo);//copy数据
            docStructTemplateInfoVo.setStTemplateName(request.getStTemplateName());
            docStructTemplateInfoService.addDocStructTemplateInfo(docStructTemplateInfoVo);//保存模板

            // 模板基本信息soid
            Long stTemplateInfoSoid = docStructTemplateInfoVo.getStTemplateInfoSoid();
            //存储到json中
            DocCustomTextJson docCustomTextJson = DocCustomTextJson.builder()
//                    .customTextJsonSoid(cmoidGanerator.getSOID())
                    .customTextJsonSoid(soidService.getSoid())
                    .stTemplateInfoSoid(stTemplateInfoSoid)
                    .reportContent(JSONObject.toJSONString(docReportVoList))
                    .isDelete(0L)
                    .createDate(new Date())
                    .build();
            docCustomTextJsonMapper.insert(docCustomTextJson);
            //存储字符串
            List<DocReportClobContent> docReportClobContentList = request.getDocReportClobContentList();
            if (CollectionUtils.isNotEmpty(docReportClobContentList)) {
                for (DocReportClobContent docReportClobContent : docReportClobContentList) {
                    DocStructTemplateClobContent docStructTemplateClobContent = new DocStructTemplateClobContent();
//                    docStructTemplateClobContent.setTemplateClobContentSoid(cmoidGanerator.getSOID());
                    docStructTemplateClobContent.setTemplateClobContentSoid(soidService.getSoid());
                    docStructTemplateClobContent.setStTemplateInfoSoid(stTemplateInfoSoid);
                    docStructTemplateClobContent.setReportContent(docReportClobContent.getReportContent());
                    docStructTemplateClobContent.setReportContentType(docReportClobContent.getReportContentType());
                    docStructTemplateClobContent.setIsDelete(0l);
                    docStructTemplateClobContent.setCreateDate(new Date());
                    docStructTemplateClobContent.setUpdateDate(new Date());
                    docStructTemplateClobContentMapper.insertSelective(docStructTemplateClobContent);
                }
            }

            buildActionSuccess(result);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("保存报告模板发送异常", e);
            buildActionWarn(result, "保存报告模板失败");
        } finally {
            stopWatch.stop();
            log.info("本次保存报告模板耗时: " + stopWatch.getTime() + "ms");
        }
        return result;
    }

    // FIXME: yutao 2021/8/8 优化

    /**
     * 接收报告，将报告改为已审核，保存报告
     *
     * @param reportRequest
     * @return
     */
    @Override
    @Transactional
    public ActionResult modifyReportStatus(DocReportPreservationRequest reportRequest) {
        ActionResult actionResult = new ActionResult();
        Long stReportSoid = reportRequest.getStReportSoid();
        if (ObjectUtils.isEmpty(reportRequest.getEmployeeSoid())) {
            buildBadRequestActionWarn(actionResult, "用户信息为空");
            return actionResult;
        }
        if (ObjectUtils.isEmpty(stReportSoid)) {
            buildBadRequestActionWarn(actionResult, "报告存储信息标识不能为空");
            return actionResult;
        }

        //查询报告状态
        DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
        if (ObjectUtils.isEmpty(docStructReport)) {
            buildBadRequestActionWarn(actionResult, "未查到报告信息");
            return actionResult;
        }
        if (ObjectUtils.isNotEmpty(docStructReport)) {
            Long reportProcessStatus = docStructReport.getReportProcessStatus();
            if (!ReportProcessStatus.TO_BE_REVIEWED.code.equals(reportProcessStatus)) {
                buildBadRequestActionWarn(actionResult, "报告状态不是待审核");
                return actionResult;
            }
        }
        //将报告存储信息的流转状态改为已审核
        // 报告修改次数加一
        docStructReport.setStEditCount(docStructReport.getStEditCount() + 1);
        docStructReport.setStReportSoid(stReportSoid);
        //将报告存储信息的流转状态改为已审核
        docStructReport.setReportProcessStatus(ReportProcessStatus.REVIEW_COMPLETED.code);
        if (ObjectUtils.isEmpty(docStructReport.getFirstTrialDoctor())) {
            docStructReport.setFirstTrialDoctor(reportRequest.getEmployeeSoid());
        } else if (ObjectUtils.isEmpty(docStructReport.getSecondTrialDoctor())) {
            docStructReport.setSecondTrialDoctor(reportRequest.getEmployeeSoid());
        }

        docStructReport.setStatus(ReportStatus.REVIEW_PASSED.code);
        docStructReport.setIsDelete(0L);
        docStructReport.setCreateDate(new Date());
        docStructReport.setUpdateDate(new Date());
        docStructReport.setPictureQuality(reportRequest.getPictureQuality());
        docStructReport.setNegativePositive(reportRequest.getNegativePositive());
        docStructReport.setReportLevel(reportRequest.getReportLevel());

        //报告和检查实例的关系
        DocReportRequisitionRelation docReportRequisitionRelation = new DocReportRequisitionRelation();
        List<DocReportRequisitionRelationVo> docReportRequisitionRelationVos =
                docReportRequisitionRelationMapper.selectByStReportSoid(stReportSoid);

        //生命周期插入数据
        Long maxSerialNo = getMaxSerialNo(docStructReport);
        DocStructReportLifeCycle docStructReportLifeCycle = new DocStructReportLifeCycle();
        Long stReportLifeCycleSoid = soidService.getSoid();
        docStructReportLifeCycle.setStReportLifeCycleSoid(stReportLifeCycleSoid);
        docStructReportLifeCycle.setStReportSoid(Long.valueOf(stReportSoid));
        docStructReportLifeCycle.setStatus(ReportStatus.REVIEW_PASSED.code);
        docStructReportLifeCycle.setReportProcessStatus(ReportProcessStatus.REVIEW_COMPLETED.code);
        docStructReportLifeCycle.setUpdateUser(reportRequest.getEmployeeSoid());
        docStructReportLifeCycle.setIsDelete(0L);
        docStructReportLifeCycle.setReportContent(JSONObject.toJSONString(reportRequest.getDocReportVoList()));
        docStructReportLifeCycle.setCreateDate(new Date());
        docStructReportLifeCycle.setUpdateDate(new Date());
        if (ObjectUtils.isNotEmpty(maxSerialNo)) {
            docStructReportLifeCycle.setSerialNo(maxSerialNo + 1);
        }
        docStructReportLifeCycleMapper.insert(docStructReportLifeCycle);

        docStructReport.setStReportLifeCycleSoid(stReportLifeCycleSoid);
        srvDocReportService.updateStructReport(docStructReport);

        //更新报告完整存储信息
        DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
        if (ObjectUtils.isNotEmpty(reportJson)) {
            if (ObjectUtils.isNotEmpty(reportRequest.getDocReportVoList())) {
                reportJson.setReportContent(JSONObject.toJSONString(reportRequest.getDocReportVoList()));
                reportJson.setUpdateDate(new Date());
                docStructReportJsonMapper.updateByPrimaryKey(reportJson);
            }
        } else {
            buildBadRequestActionWarn(actionResult, "未查到申请单对应报告存储信息");
            return actionResult;
        }

        // 逻辑删除报告存储图片
        docStructReportImgMapper.deleteByStReportSoid(stReportSoid);
        // 报告图片存储
//        List<DocStructReportImgVo> imgList = reportRequest.getDocReportVo().getDocStructReportImgVoList();
        List<DocReportVo> docReportVoList = reportRequest.getDocReportVoList();
        if (ObjectUtils.isNotEmpty(docReportVoList)) {
            for (DocReportVo docReportVo : docReportVoList) {
                List<DocStructReportImgVo> imgList = docReportVo.getDocStructReportImgVoList();
                if (CollectionUtils.isNotEmpty(imgList)) {
                    for (int i = 0; i < imgList.size(); i++) {
                        DocStructReportImgVo img = imgList.get(i);
                        DocStructReportImg target = new DocStructReportImg();
                        BeanUtils.copyProperties(img, target);
                        Long imgSoid = soidService.getSoid();
//                Long imgSoid = cmoidGanerator.getSOID();
                        img.setStReportImgSoid(imgSoid);
                        img.setCreateDate(new Date());
                        img.setUpdateDate(new Date());
                        img.setIsDelete(0L);
                        img.setUpdateUser(reportRequest.getEmployeeSoid());
                        img.setStReportSoid(stReportSoid);
                        docStructReportImgMapper.insert(target);

                        // 国标
                        soidService.insertOid(imgSoid, 4);
                    }
                }

            }
        }

        buildActionSuccess(actionResult);
        return actionResult;
    }

    /**
     * 退回报告,将报告改为审核已退回
     *
     * @param stReportSoid
     * @param employeeSoid
     * @return
     */
    @Override
    @Transactional
    public ActionResult modifyStatus(String stReportSoid, Long employeeSoid) {
        ActionResult actionResult = new ActionResult();
        if (ObjectUtils.isEmpty(employeeSoid)) {
            buildBadRequestActionWarn(actionResult, "用户信息为空");
            return actionResult;
        }
        if (StringUtils.isNotBlank(stReportSoid)) {
            //查询报告状态
            DocStructReport docStructReport = null;
            docStructReport = docStructReportMapper.selectByPrimaryKey(Long.parseLong(stReportSoid));
            if (ObjectUtils.isEmpty(docStructReport)) {
                buildBadRequestActionWarn(actionResult, "未查到报告信息");
                return actionResult;
            }
            if (ObjectUtils.isNotEmpty(docStructReport)) {
                Long reportProcessStatus = docStructReport.getReportProcessStatus();
                if (!ReportProcessStatus.TO_BE_REVIEWED.code.equals(reportProcessStatus)) {
                    buildBadRequestActionWarn(actionResult, "报告状态不是待审核");
                    return actionResult;
                }
            }
            //将流转状态改为待书写
            docStructReport.setStReportSoid(Long.parseLong(stReportSoid));
            docStructReport.setReportProcessStatus(ReportProcessStatus.TO_BE_WRITTEN.code);
            docStructReport.setStatus(ReportStatus.REVIEW_RETURNED.code);
            docStructReport.setIsDelete(0L);
            docStructReport.setCreateDate(new Date());
            docStructReport.setUpdateDate(new Date());
            docStructReport.setFirstTrialDoctor(null);
//            srvDocReportService.updateStructReportSelective(docStructReport);

            //生命周期插入数据
            Long maxSerialNo = getMaxSerialNo(docStructReport);
            DocStructReportLifeCycle docStructReportLifeCycle = new DocStructReportLifeCycle();
            Long stReportLifeCycleSoid = soidService.getSoid();

            docStructReportLifeCycle.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            docStructReportLifeCycle.setReportProcessStatus(ReportProcessStatus.TO_BE_WRITTEN.code);
            docStructReportLifeCycle.setStatus(ReportStatus.REVIEW_RETURNED.code);
            docStructReportLifeCycle.setStReportSoid(Long.valueOf(stReportSoid));
            docStructReportLifeCycle.setUpdateUser(employeeSoid);
            docStructReportLifeCycle.setIsDelete(0L);
            docStructReportLifeCycle.setCreateDate(new Date());
            docStructReportLifeCycle.setUpdateDate(new Date());
            if (ObjectUtils.isNotEmpty(maxSerialNo)) {
                docStructReportLifeCycle.setSerialNo(maxSerialNo + 1);
            }
            docStructReportLifeCycleMapper.insert(docStructReportLifeCycle);

            docStructReport.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            srvDocReportService.updateStructReport(docStructReport);
            buildActionSuccess(actionResult);
            return actionResult;
        }
        buildActionWarn(actionResult, "参数不能为空");
        return actionResult;
    }

    /**
     * 报告通过审核,撤回报告
     *
     * @param stReportSoid
     * @param employeeSoid
     * @return
     */
    @Override
    @Transactional
    public ActionResult withdrawStatus(String stReportSoid, Long employeeSoid) {
        ActionResult actionResult = new ActionResult();
        if (ObjectUtils.isEmpty(employeeSoid)) {
            buildBadRequestActionWarn(actionResult, "用户信息为空");
            return actionResult;
        }
        if (StringUtils.isNotBlank(stReportSoid)) {
            //查询报告状态
            DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(Long.parseLong(stReportSoid));
            if (ObjectUtils.isEmpty(docStructReport)) {
                buildBadRequestActionWarn(actionResult, "未查到报告信息");
                return actionResult;
            }
            if (ObjectUtils.isNotEmpty(docStructReport)) {
                Long reportProcessStatus = docStructReport.getReportProcessStatus();
                if (!ReportProcessStatus.REVIEW_COMPLETED.code.equals(reportProcessStatus)) {
                    buildBadRequestActionWarn(actionResult, "报告未审核完成");
                    return actionResult;
                }
            }
            //将流转状态改为待审核
            docStructReport.setStReportSoid(Long.parseLong(stReportSoid));
            docStructReport.setReportProcessStatus(ReportProcessStatus.TO_BE_REVIEWED.code);
            docStructReport.setStatus(ReportStatus.REVIEW_RECALLED.code);
            docStructReport.setFirstTrialDoctor(null);
            docStructReport.setIsDelete(0L);
            docStructReport.setCreateDate(new Date());
            docStructReport.setUpdateDate(new Date());
//            srvDocReportService.updateStructReportSelective(docStructReport);

            //生命周期插入数据
            Long maxSerialNo = getMaxSerialNo(docStructReport);
            DocStructReportLifeCycle docStructReportLifeCycle = new DocStructReportLifeCycle();
            Long stReportLifeCycleSoid = soidService.getSoid();
            docStructReportLifeCycle.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            docStructReportLifeCycle.setReportProcessStatus(ReportProcessStatus.TO_BE_REVIEWED.code);
            docStructReportLifeCycle.setStatus(ReportStatus.REVIEW_RECALLED.code);
            docStructReportLifeCycle.setStReportSoid(Long.valueOf(stReportSoid));
            docStructReportLifeCycle.setIsDelete(0L);
            docStructReportLifeCycle.setCreateDate(new Date());
            docStructReportLifeCycle.setUpdateDate(new Date());
            if (ObjectUtils.isNotEmpty(maxSerialNo)) {
                docStructReportLifeCycle.setSerialNo(maxSerialNo + 1);
            }
            docStructReportLifeCycle.setUpdateUser(employeeSoid);
            docStructReportLifeCycleMapper.insert(docStructReportLifeCycle);

            docStructReport.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            srvDocReportService.updateStructReportSelective(docStructReport);

            buildActionSuccess(actionResult);
            return actionResult;
        }
        buildActionWarn(actionResult, "参数不能为空");
        return actionResult;
    }

    @Override
    public ActionResult saveStructuredReport(StructuredReportRequest request) {
        log.info("开始保存结构化报告");
        StopWatch stopWatch = StopWatch.createStarted();
        ActionResult actionResult = new ActionResult();

        try {
            // 业务态报告结构基本信息
            for (DocReportVo docReportVo : request.getDocReportVoList()) {
                saveStruct(docReportVo, request.getStReportSoid());
            }

            buildActionSuccess(actionResult);
        } catch (Exception e) {
            log.error("保存结构化报告发送异常", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            buildActionWarn(actionResult, "保存结构化报告失败");
        } finally {
            stopWatch.stop();
            log.info("本次保存结构化报告耗时: " + stopWatch.getTime() + "ms");
        }

        return actionResult;
    }

    // FIXME: yutao 2021/8/8 优化
    @Override
    public ListResult<ReportResult> getDocReportByTypes(DocReportInitializationRequest request) {
        log.info("开始报告回显,回显条件: " + request);
        StopWatch stopWatch = StopWatch.createStarted();
        ListResult<ReportResult> result = new ListResult<>();
        if (ObjectUtils.isEmpty(request.getRequestSoid())) {
            log.error("申请单标识不能为空");
            buildBadRequestListWarn(result, "申请单标识不能为空");
            return result;
        }

        // TODO 后面要加上限制
//        if (ObjectUtils.isEmpty(request.getExaminationVisitSoid())) {
//            log.error("检查标识不能为空");
//            buildBadRequestListWarn(result, "检查标识不能为空");
//            return result;
//        }

        if (ObjectUtils.isEmpty(request.getEmployeeSoid())) {
            buildBadRequestListWarn(result, "用户信息为空");
            return result;
        }
//        List<DocReportRequisitionRelationVo> relationVoList = new ArrayList<>();
        DocReportRequisitionRelationVo docReportRequisitionRelationVo = null;
        Long employeeSoid = request.getEmployeeSoid();
        // TODO DELETE OR NOT?
        Long parameterValueSoid = null;
        //前台传来的
        Map<String, String> docReportInitializationMap = request.getDocReportInitializationMap();
        if (ObjectUtils.isNotEmpty(docReportInitializationMap.get("parameterValueSoid"))) {
            parameterValueSoid = Long.parseLong(docReportInitializationMap.get("parameterValueSoid"));
        }
        if (!ObjectUtils.isEmpty(employeeSoid)) {

//            if (ReportType.WRITE_REPORT_REQUEST.code.equals(parameterValueSoid)) {
//
//                relationVoList = docReportRequisitionRelationMapper.selectByRequestSoid(request.getRequestSoid());
//
//            } else if (ReportType.WRITE_REPORT_EXAMINATIONVISITSOID.code.equals(parameterValueSoid)) {
//
//                relationVoList = docReportRequisitionRelationMapper.selectByExam(Long.valueOf(request.getExaminationVisitSoid()));
//
//            } else if (ReportType.WRITE_REPORT_REGISTRATIONNO.code.equals(parameterValueSoid)) {
//
//                relationVoList = docReportRequisitionRelationMapper.selectByRegistrationNo(request.getRegistrationNo());
//
//            }

            // 根据申请单标识,登记单标识,检查单标识查询
            docReportRequisitionRelationVo = docReportRequisitionRelationMapper.selectAccurateReport(request.getRequestSoid(),
                    StringUtils.isNotEmpty(request.getRegistrationFormSoid()) ? Long.valueOf(request.getRegistrationFormSoid()) : null,
                    StringUtils.isNotEmpty(request.getExaminationVisitSoid()) ? Long.valueOf(request.getExaminationVisitSoid()) : null);

        }

        try {
            if (ObjectUtils.isNotEmpty(docReportRequisitionRelationVo)) {
                // 报告存储信息标识
                Long stReportSoid = docReportRequisitionRelationVo.getStReportSoid();
                if (stReportSoid != null) {
                    // 报告存储信息
                    DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
                    // 报告完整存储(json)
                    DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
                    if (reportJson != null) {
                        // 报告流转状态
                        String reportProcessStatus = null;
                        Long reportStatus = null;
                        if (docStructReport != null) {
                            Long processStatus = docStructReport.getReportProcessStatus();
                            reportStatus = docStructReport.getStatus();
                            if (processStatus != null) {
                                if (processStatus.longValue() == ReportProcessStatus.TO_BE_WRITTEN.code) {
                                    // 待书写
                                    reportProcessStatus = ReportProcessStatus.TO_BE_WRITTEN.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.PRINT_COMPLETED.code) {
                                    // 打印完成
                                    reportProcessStatus = ReportProcessStatus.PRINT_COMPLETED.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.REVIEW_COMPLETED.code) {
                                    // 审核完成
                                    reportProcessStatus = ReportProcessStatus.REVIEW_COMPLETED.name;
                                }
                                if (processStatus.longValue() == ReportProcessStatus.TO_BE_REVIEWED.code) {
                                    // 初写完成待审核
                                    reportProcessStatus = ReportProcessStatus.TO_BE_REVIEWED.name;
                                }
                            }
                        }
                        String reportContent = reportJson.getReportContent();
                        String emergencySign = null;
                        Long stTemplateInfoSoid = reportJson.getStTemplateInfoSoid();

                        if (ObjectUtils.isNotEmpty(docReportInitializationMap.get("emergencySign"))) {
                            emergencySign = docReportInitializationMap.get("emergencySign");
                        }
                        if (StringUtils.isNotEmpty(reportContent) && stTemplateInfoSoid != null) {
                            // 报告
                            List<DocReportVo> docReportVoList = JSONObject.parseArray(reportContent, DocReportVo.class);
                            ReportResult report = new ReportResult();
                            // 报告模板soid
                            report.setStTemplateInfoSoid(stTemplateInfoSoid);
                            // 报告
                            report.setDocReportVoList(docReportVoList);
                            // 报告流转状态
                            report.setReportProcessStatus(reportProcessStatus);
                            // 报告存储信息soid
                            report.setStReportSoid(stReportSoid);
                            // 报告自身状态
                            report.setReportStatus(reportStatus.toString());
                            // 报告加急状态
                            if (emergencySign != null) {
                                report.setEmergencySign(emergencySign);
                            }

                            // 添加特殊段落模块信息
                            List<DocReportClobContent> docReportClobContents =
                                    docReportClobContentMapper.selectByStReportSoid(stReportSoid);
                            report.setDocReportClobContentList(docReportClobContents);

                            buildListSuccess(result, report);
                        }
                    }
                }
            }

        } catch (Exception e) {
            log.error("报告回显发送异常", e);
            buildListWarn(result, "报告回显失败");
        } finally {
            stopWatch.stop();
            log.info("本次报告回显耗时: " + stopWatch.getTime() + "ms");
        }
        return result;
    }

    @Override
    public List<DocReportRequisitionRelationVo> selectByStReportSoid(Long stReportSoid) {
        List<DocReportRequisitionRelationVo> docReportRequisitionRelationVos = docReportRequisitionRelationMapper.selectByStReportSoid(stReportSoid);
        return docReportRequisitionRelationVos;
    }


    @Override
    public ListResult<StatusSum> queryReportsNumbers(QueryReportsNumberDto queryReportsNumberDto) {
        String completedCode = queryReportsNumberDto.getCompletedCode();
        Long employeeSoid = queryReportsNumberDto.getEmployeeSoid();
        String writtenCode = queryReportsNumberDto.getWrittenCode();
        ListResult<StatusSum> listResult = new ListResult();
        StatusSum statusSum = new StatusSum();
        if (StringUtils.isBlank(writtenCode)) {
            int count = docStructReportMapper.queryCompletedReportsNumbers(employeeSoid, completedCode);
            statusSum.setAccomplishSum(count);
        } else if (StringUtils.isBlank(completedCode)) {
            int count1 = docStructReportMapper.queryWrittenReportsNumbers(employeeSoid, writtenCode);
            statusSum.setWriteSum(count1);
        }

        buildListSuccess(listResult, statusSum);
        return listResult;
    }

    @Override
    public ActionResult publishReport(ReportPublishRequest reportPublishRequest) {
        log.info("开始发布报告");
        StopWatch stopWatch = StopWatch.createStarted();
        ActionResult actionResult = new ActionResult();
        try {
            if (CollectionUtils.isEmpty(reportPublishRequest.getStReportSoidList())) {
                buildActionWarn(actionResult, "报告存储信息标识不能为空");
                return actionResult;
            }

            List<ExistedReportResult> existedReportResults = docStructReportMapper.selectExistedReport(reportPublishRequest.getStReportSoidList());
            if (CollectionUtils.isNotEmpty(existedReportResults)) {
                for (ExistedReportResult existedReportResult : existedReportResults) {
                    if (existedReportResult.getReportNumber() == 0) {
                        buildActionWarn(actionResult, "报告不存在,stReportSoid: " + existedReportResult.getStReportSoid());
                        return actionResult;
                    }
                }
            }

            List<ExistedReportResult> reportStatusResults = docStructReportMapper.selectReportStatus(reportPublishRequest.getStReportSoidList());
            if (CollectionUtils.isNotEmpty(reportStatusResults)) {
                for (ExistedReportResult reportStatusResult : reportStatusResults) {
                    if (reportStatusResult.getReportStatus() == null) {
                        buildActionWarn(actionResult, "报告自身状态为空,stReportSoid: " + reportStatusResult.getStReportSoid());
                        return actionResult;
                    }
                    if (ReportStatus.REVIEW_PASSED.code.longValue() != reportStatusResult.getReportStatus().longValue()) {
                        buildActionWarn(actionResult, "报告尚未已审通过,无法发布");
                        return actionResult;
                    }
                }
            }

            for (Long stReportSoid : reportPublishRequest.getStReportSoidList()) {
                DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
                if (docStructReport != null) {
                    // 修改报告存储信息中的报告相关状态
                    // 将报告存储信息的流转状态改为发布完成
                    docStructReport.setReportProcessStatus(ReportProcessStatus.PUBLISH_COMPLETED.code);
                    // 将报告存储信息的报告自身状态改为已发布
                    docStructReport.setStatus(ReportStatus.PUBLISH_COMPLETED.code);
                    docStructReport.setCreateDate(new Date());
                    docStructReport.setUpdateDate(new Date());
                    docStructReport.setUpdateUser(reportPublishRequest.getEmployeeSoid());

                    // 生命周期插入数据
                    Long maxSerialNo = getMaxSerialNo(docStructReport);
                    DocStructReportLifeCycle docStructReportLifeCycle = new DocStructReportLifeCycle();
                    Long stReportLifeCycleSoid = soidService.getSoid();
                    docStructReportLifeCycle.setStReportLifeCycleSoid(stReportLifeCycleSoid);
                    docStructReportLifeCycle.setStReportSoid(stReportSoid);
                    docStructReportLifeCycle.setStatus(ReportStatus.PUBLISH_COMPLETED.code);
                    docStructReportLifeCycle.setReportProcessStatus(ReportProcessStatus.PUBLISH_COMPLETED.code);
                    docStructReportLifeCycle.setUpdateUser(reportPublishRequest.getEmployeeSoid());
                    docStructReportLifeCycle.setIsDelete(0L);
                    docStructReportLifeCycle.setCreateDate(new Date());
                    docStructReportLifeCycle.setUpdateDate(new Date());
                    if (ObjectUtils.isNotEmpty(maxSerialNo)) {
                        docStructReportLifeCycle.setSerialNo(maxSerialNo + 1);
                    }
                    docStructReportLifeCycleMapper.insert(docStructReportLifeCycle);

                    docStructReport.setStReportLifeCycleSoid(stReportLifeCycleSoid);
                    srvDocReportService.updateStructReportSelective(docStructReport);
                }
            }
            buildActionSuccess(actionResult);

            // TODO 报告发布通知上游申请单
        } catch (Exception e) {
            log.error("本次发布报告发送异常", e);
            buildActionWarn(actionResult, "本次发布报告发送失败");
        } finally {
            stopWatch.stop();
            log.info("本次发布报告耗时: " + stopWatch.getTime() + "ms");
        }
        return actionResult;
    }

    @Override
    public ActionResult recallReport(ReportRecallRequest reportRecallRequest) {
        log.info("开始召回报告");
        StopWatch stopWatch = StopWatch.createStarted();
        ActionResult actionResult = new ActionResult();
        try {
            if (ObjectUtils.isEmpty(reportRecallRequest.getStReportSoid())) {
                buildActionWarn(actionResult, "报告存储信息标识不能为空");
                return actionResult;
            }

            DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(reportRecallRequest.getStReportSoid());
            if (docStructReport == null) {
                buildActionWarn(actionResult, "报告不存在,无法召回");
                return actionResult;
            }

            if (docStructReport.getStatus() == null) {
                buildActionWarn(actionResult, "报告自身状态为空");
                return actionResult;
            }

            if (ReportStatus.PUBLISH_COMPLETED.code.longValue() != docStructReport.getStatus().longValue()) {
                buildActionWarn(actionResult, "报告尚未发布,无法召回");
                return actionResult;
            }

            long publishTime = docStructReport.getUpdateDate().getTime();
            long recallTime = new Date().getTime();
            int gap = (int) ((recallTime - publishTime) / 1000);
            if (gap > reportRecallRequest.getRecallTimeLimit()) {
                buildActionWarn(actionResult, "超出报告召回有效时间");
                return actionResult;
            }

            // TODO 校验报告是否被上游引用

            // 修改报告存储信息中的报告相关状态
            // 将报告存储信息的流转状态改为审核完成
            docStructReport.setReportProcessStatus(ReportProcessStatus.REVIEW_COMPLETED.code);
            // 将报告存储信息的报告自身状态改为发布召回
            docStructReport.setStatus(ReportStatus.PUBLISH_BACK.code);
            docStructReport.setCreateDate(new Date());
            docStructReport.setUpdateDate(new Date());
            docStructReport.setUpdateUser(reportRecallRequest.getEmployeeSoid());

            // 生命周期插入数据
            Long maxSerialNo = getMaxSerialNo(docStructReport);
            DocStructReportLifeCycle docStructReportLifeCycle = new DocStructReportLifeCycle();
            Long stReportLifeCycleSoid = soidService.getSoid();
            docStructReportLifeCycle.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            docStructReportLifeCycle.setStReportSoid(reportRecallRequest.getStReportSoid());
            docStructReportLifeCycle.setStatus(ReportStatus.PUBLISH_BACK.code);
            docStructReportLifeCycle.setReportProcessStatus(ReportProcessStatus.REVIEW_COMPLETED.code);
            docStructReportLifeCycle.setUpdateUser(reportRecallRequest.getEmployeeSoid());
            docStructReportLifeCycle.setIsDelete(0L);
            docStructReportLifeCycle.setCreateDate(new Date());
            docStructReportLifeCycle.setUpdateDate(new Date());
            if (ObjectUtils.isNotEmpty(maxSerialNo)) {
                docStructReportLifeCycle.setSerialNo(maxSerialNo + 1);
            }
            docStructReportLifeCycleMapper.insert(docStructReportLifeCycle);

            docStructReport.setStReportLifeCycleSoid(stReportLifeCycleSoid);
            srvDocReportService.updateStructReportSelective(docStructReport);
            buildActionSuccess(actionResult);

            // TODO 报告发布通知上游申请单
        } catch (Exception e) {
            log.error("本次召回报告发送异常", e);
            buildActionWarn(actionResult, "本次召回报告发送失败");
        } finally {
            stopWatch.stop();
            log.info("本次召回报告耗时: " + stopWatch.getTime() + "ms");
        }
        return actionResult;
    }


    private void addNoumenon(List<DocStructTemplateSlotVo> docStructTemplateSlotVoList, DocReportParagraphVo docReportParagraphVo,
                             DocReportFragmentVo docReportFragmentVo, Long stReportSoid) {
        //处理slot中本体数据
        Map<Long, List<DocStructTemplateSlotVo>> map = docStructTemplateSlotVoList
                .stream()
                .filter(m -> m.getIndividualSoid() == null)
                .collect(Collectors.groupingBy(DocStructTemplateSlotVo::getNoumenonSoid));
        for (List<DocStructTemplateSlotVo> docStructTemplateSlotVos : map.values()) {
            DocStructTemplateSlotVo docStructTemplateSlotVo = docStructTemplateSlotVos.get(0);
            //2.2.2.设置报告结构基本信息,添加到数据库中
            DocBusinessStructReport docBusinessStructReport = new DocBusinessStructReport();
//            docBusinessStructReport.setIndividualSoid(docStructTemplateSlotVo.getIndividualSoid());
//            docBusinessStructReport.setIndividualName(docStructTemplateSlotVo.getIndividualName());
            docBusinessStructReport.setNoumenonSoid(docStructTemplateSlotVo.getNoumenonSoid());
            Long structInfoSoid = soidService.getSoid();//业务态报告结构基本信息标识
            docBusinessStructReport.setBnsStructInfoSoid(structInfoSoid);
            docBusinessStructReport.setStReportSoid(stReportSoid);//设置报告存储信息标识
            docBusinessStructReport.setIsDelete(0L);
            docBusinessStructReport.setCreateDate(new Date());
            docBusinessStructReport.setUpdateDate(new Date());
            docBusinessStructReportMapper.insertSelective(docBusinessStructReport);

            //2.2.3.设置实例上下文信息，添加到数据库中
            DocBusinessStructIndividual docBusinessStructIndividual =
                    new DocBusinessStructIndividual();
            docBusinessStructIndividual.setStParagraphSoid(docReportParagraphVo.getStParagraphSoid());//设置实例上下文段落标识
            docBusinessStructIndividual.setStFragmentSoid(docReportFragmentVo.getStFragmentSoid());
            docBusinessStructIndividual.setIsDelete(0L);
            docBusinessStructIndividual.setCreateDate(new Date());
            docBusinessStructIndividual.setUpdateDate(new Date());
            docBusinessStructIndividual.setBnsStructInfoSoid(structInfoSoid);//设置报告结构基本信息标识
            docBusinessStructIndividual.setBnsStIndSoid(soidService.getSoid());
            docBusinessStructIndividualMapper.insertSelective(docBusinessStructIndividual);
            List<DocStructTemplateSlotVo> docStructTemplateSlotVoValues =
                    docStructTemplateSlotVoList.stream()
                            .filter(m -> StringUtils.isNoneEmpty(m.getDocStructSlotValueVo().getDataValue()))
                            .collect(Collectors.toList());//过滤片段slotvalue为空的情况
            for (DocStructTemplateSlotVo docStructTemplateSlotVo1 : docStructTemplateSlotVoValues) {
                saveIndividualSlot(structInfoSoid, docStructTemplateSlotVo1);
            }
        }
    }


    /**
     * 暂缓报告
     *
     * @param
     * @return
     */
    @Override
    public ActionResult postponeReport(String requestSoid, String personSoid, String registrationFormSoid) {
        ActionResult actionResult = new ActionResult();
        try {
            Long operator = StringUtils.isNotEmpty(personSoid) ? Long.valueOf(personSoid) : null;
            Long registrationForm = StringUtils.isNotEmpty(registrationFormSoid) ? Long.valueOf(registrationFormSoid) : null;
            //查询当前患者是否有报告
            DocReportRequisitionRelation relation = docReportRequisitionRelationMapper.selectReport(Long.valueOf(requestSoid), operator, registrationForm);
            if (null != relation) {
                Long stReportSoid = relation.getStReportSoid();
                //删除报告
                docStructReportMapper.updatePostponeStatus(stReportSoid);
                //删除报告生命周期
                docStructReportLifeCycleMapper.updatePostponeLifeCycleStatus(stReportSoid);
                //删除报告PDF
                docStructReportPdfMapper.updatePostponePdfStatus(stReportSoid);
                //删除报告完整存储
                docStructReportJsonMapper.updatePostponeJsonStatus(stReportSoid);
                //删除报告图片
                docStructReportImgMapper.deleteByStReportSoid(stReportSoid);
            }
            buildActionSuccess(actionResult);
        } catch (NumberFormatException e) {
            log.error("暂缓报告发送异常", e);
            buildActionWarn(actionResult, "暂缓报告发送失败");
        }
        return actionResult;
    }

    /**
     * 非首次签署报告
     *
     * @param request
     * @param docStructReport
     * @return
     */
    public Long saveNoFirst(DocReportPreservationRequest request, DocStructReport docStructReport, ReportIds reportIds) {

        Long employeeSoid = reportIds.getEmployeeSoid();
        String customerSoid = reportIds.getCustomerSoid();
        String apntPersonSoid = reportIds.getApntPersonSoid();
        String patientSoid = reportIds.getPatientSoid();

        Long stReportSoid = request.getStReportSoid();

        // 逻辑删除报告相关记录
        // 业务态报告结构基本信息
        List<DocBusinessStructReportVo> docBusinessStructReportList =
                docBusinessStructReportMapper.selectByStReportSoid(stReportSoid);
        if (CollectionUtils.isNotEmpty(docBusinessStructReportList)) {
            List<Long> bnsStructInfoSoidList = new ArrayList<>();
            for (int i = 0; i < docBusinessStructReportList.size(); i++) {
                bnsStructInfoSoidList.add(docBusinessStructReportList.get(i).getBnsStructInfoSoid());
            }
            if (CollectionUtils.isNotEmpty(bnsStructInfoSoidList)) {
                // 逻辑删除实例上下文信息
                docBusinessStructIndividualMapper.deleteByBnsStructInfoSoidList(bnsStructInfoSoidList);
                // 逻辑删除报告结构实例slot值信息
                docBusinessStructSlotMapper.deleteByBnsStructInfoSoidList(bnsStructInfoSoidList);
                // 逻辑删除业务态报告结构基本信息
                docBusinessStructReportMapper.deleteByPrimaryKeyList(bnsStructInfoSoidList);
            }
        }
        // 逻辑删除报告存储图片
        docStructReportImgMapper.deleteByStReportSoid(stReportSoid);


        // 更新报告存储信息
        if (ObjectUtils.isNotEmpty(docStructReport)) {
            // 报告修改次数加一
            docStructReport.setStEditCount(docStructReport.getStEditCount() + 1);
            docStructReport.setUpdateDate(new Date());
            // 设置报告状态和报告流转状态
            docStructReport.setStatus(request.getReportStatus());
            docStructReport.setReportProcessStatus(request.getReportProcessStatus());
            docStructReport.setUpdateUser(employeeSoid);
            // 超声报告签署时即打分(阴阳性)
            docStructReport.setNegativePositive(request.getNegativePositive());
            if (StringUtils.isNotEmpty(customerSoid)) {
                docStructReport.setCustomerSoid(Long.valueOf(customerSoid));
            }
            if (StringUtils.isNotEmpty(apntPersonSoid)) {
                docStructReport.setApntPersonSoid(Long.valueOf(apntPersonSoid));

            }
            if (StringUtils.isNotEmpty(patientSoid)) {
                docStructReport.setPatientSoid(Long.valueOf(patientSoid));
            }
            // 更新报告完整存储信息
            DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
            if (reportJson != null) {
                if (ObjectUtils.isNotEmpty(request.getDocReportVoList())) {
//                                reportJson.setReportContent(JSONObject.toJSONString(request.getDocReportVo()));
                    reportJson.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
                    reportJson.setUpdateDate(new Date());
                    docStructReportJsonMapper.updateByPrimaryKey(reportJson);
                }
            }
        }

        // 新增报告生命周期
        Long maxSerialNo = getMaxSerialNo(docStructReport);
        Long lifeCycleSoid = saveReportLifeCycle(request, employeeSoid, stReportSoid, maxSerialNo + 1);
        docStructReport.setStReportLifeCycleSoid(lifeCycleSoid);
        srvDocReportService.updateStructReportSelective(docStructReport);
        return stReportSoid;
    }

    /**
     * 首次签署报告
     *
     * @param request
     */
    public Long saveFirst(DocReportPreservationRequest request, ReportIds reportIds) {

        Long employeeSoid = reportIds.getEmployeeSoid();
        String customerSoid = reportIds.getCustomerSoid();
        String apntPersonSoid = reportIds.getApntPersonSoid();
        String patientSoid = reportIds.getPatientSoid();

        // 新增报告存储信息
        DocStructReport report = new DocStructReport();
//                stReportSoid = cmoidGanerator.getSOID();
        Long stReportSoid = soidService.getSoid();
        report.setStReportSoid(stReportSoid);
        // 修改报告状态和报告流转状态
        report.setReportProcessStatus(request.getReportProcessStatus());
        report.setStatus(request.getReportStatus());
        report.setStEditCount(0);
        report.setIsDelete(0L);
        report.setCreateDate(new Date());
        report.setUpdateDate(new Date());
        report.setUpdateUser(employeeSoid);
        report.setFirstWriteDoctor(employeeSoid);
        //设置报告流水号(来自应用层)
        report.setReportVisitSoid(request.getReportVisitSoid());
        // 超声报告签署时即打分(阴阳性)
        report.setNegativePositive(request.getNegativePositive());
        if (StringUtils.isNotEmpty(customerSoid)) {
            report.setCustomerSoid(Long.valueOf(customerSoid));
        }

        if (StringUtils.isNotEmpty(apntPersonSoid)) {
            report.setApntPersonSoid(Long.valueOf(apntPersonSoid));
        }

        if (StringUtils.isNotEmpty(patientSoid)) {
            report.setPatientSoid(Long.valueOf(patientSoid));
        }

        // 国标
        soidService.insertOid(stReportSoid, 4);

        // 新增报告完整存储信息
        DocStructReportJson reportJson = new DocStructReportJson();
        Long reportJsonSoid = soidService.getSoid();
        // 结构化报告完整存储标识
        reportJson.setStReportJsonSoid(reportJsonSoid);
        // 结构化模板基本信息标识
        reportJson.setStTemplateInfoSoid(request.getStTemplateInfoSoid());
        // 报告单内容
        reportJson.setReportContent(JSONObject.toJSONString(request.getDocReportVoList()));
        // 报告存储信息标识
        reportJson.setStReportSoid(stReportSoid);
        reportJson.setCreateDate(new Date());
        reportJson.setUpdateDate(new Date());
        reportJson.setUpdateUser(employeeSoid);
        reportJson.setIsDelete(0L);
        docStructReportJsonMapper.insert(reportJson);


        // 按申请单写报告
        if (ReportType.WRITE_REPORT_REQUEST.code.longValue() == request.getReportType()) {
            if (CollectionUtils.isNotEmpty(request.getMsdServiceInstanceSoidList())) {
                int s = 0;
                int size = request.getMsdServiceInstanceSoidList().size();
                //获取指定数量的soid
                List<Long> soids = soidService.getSoids(size);
                for (int i = 0; i < request.getMsdServiceInstanceSoidList().size(); i++) {
                    Long relationSoid = soids.get(s++);
                    // 新增报告和检查实例的关系
                    DocReportRequisitionRelation relation = createDocReportRequisitionRelation(request, employeeSoid, stReportSoid, i, relationSoid);
                    docReportRequisitionRelationMapper.insert(relation);
                }
                //批量插入oid
                soidService.insertOids(soids, 4);
            }
            // 按登记号或上机号写报告
        } else if (ReportType.WRITE_REPORT_REGISTRATIONNO.code.longValue() == request.getReportType() ||
                ReportType.WRITE_REPORT_EXAMINATIONVISITSOID.code.longValue() == request.getReportType()) {
            //若docReportListVos不为空则为合单情况，为空且instanceVoList不为空则为未合单情况
            List<DocReportListVo> docReportListVos = request.getDocReportListVos();
            List<ServiceInstanceVo> instanceVoList = request.getServiceInstanceVoList();
            if (CollectionUtils.isNotEmpty(docReportListVos)) {
                for (DocReportListVo docReportListVo : docReportListVos) {
                    List<ServiceInstanceVo> serviceInstanceVoList = docReportListVo.getServiceInstanceVoList();
                    //登记标识
                    Long registrationFormSoid = docReportListVo.getRegistrationFormSoid();
                    //登记号
                    String registrationNo = docReportListVo.getRegistrationNo();
                    //申请单标识
                    Long requestSoid = docReportListVo.getRequestSoid();
                    //检查标识
                    Long examinationVisitSoid = docReportListVo.getExaminationVisitSoid();
                    if (CollectionUtils.isNotEmpty(serviceInstanceVoList)) {
                        int s = 0;
                        int size = serviceInstanceVoList.size();
                        //获取指定数量的soid
                        List<Long> soids = soidService.getSoids(size);
                        for (ServiceInstanceVo serviceInstanceVo : serviceInstanceVoList) {
                            Long relationSoid = soids.get(s++);
                            // 新增报告和检查实例的关系
                            DocReportRequisitionRelation relation = createDocReportRequisitionRelation(request, employeeSoid, stReportSoid, registrationFormSoid, registrationNo, requestSoid, examinationVisitSoid, serviceInstanceVo, relationSoid);
                            docReportRequisitionRelationMapper.insert(relation);
                        }
                        //批量插入oid
                        soidService.insertOids(soids, 4);
                    }
                }
            } else if (CollectionUtils.isNotEmpty(instanceVoList)) {
                int s = 0;
                int size = instanceVoList.size();
                //获取指定数量的soid
                List<Long> soids = soidService.getSoids(size);
                Long requestSoid = request.getRequestSoid();
                String registrationNo = request.getRegistrationNo();
                String registrationFormSoid = null;
                Long examinationVisitSoid = request.getExaminationVisitSoid();
                for (ServiceInstanceVo serviceInstanceVo : instanceVoList) {
                    Long relationSoid = soids.get(s++);
                    // 新增报告和检查实例的关系
                    DocReportRequisitionRelation relation = createDocReportRequisitionRelation(request, employeeSoid, stReportSoid, requestSoid, registrationNo, examinationVisitSoid, serviceInstanceVo, relationSoid);
                    docReportRequisitionRelationMapper.insert(relation);
                }
                //批量插入oid
                soidService.insertOids(soids, 4);
            }
        }
        // 新增报告生命周期信息
        Long lifeCycleSoid = saveReportLifeCycle(request, employeeSoid, stReportSoid, 1L);
        report.setStReportLifeCycleSoid(lifeCycleSoid);
        srvDocReportService.insertStructReport(report);
        return stReportSoid;
    }

    private DocReportRequisitionRelation createDocReportRequisitionRelation(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid, int i, Long relationSoid) {
        DocReportRequisitionRelation relation = new DocReportRequisitionRelation();

        // 登记号
        if (ObjectUtils.isNotEmpty(request.getRegistrationFormSoid())) {
            relation.setRegistrationFormSoid(request.getRegistrationFormSoid());
        }
        if (ObjectUtils.isNotEmpty(request.getExaminationVisitSoid())) {
            relation.setOperatorSoid(request.getExaminationVisitSoid());
        }
        // 服务实例
        relation.setMsdServiceInstanceSoid(Long.valueOf(request.getMsdServiceInstanceSoidList().get(i)));
        addDocReportRequisitionRelationCommonInfo(request, employeeSoid, stReportSoid, request.getRegistrationNo(), request.getRequestSoid(), relationSoid, relation);
        return relation;
    }

    private DocReportRequisitionRelation createDocReportRequisitionRelation(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid, Long registrationFormSoid,
                                                                            String registrationNo, Long requestSoid, Long operatorSoid,
                                                                            ServiceInstanceVo serviceInstanceVo, Long relationSoid) {
        DocReportRequisitionRelation relation = new DocReportRequisitionRelation();

        relation.setRegistrationFormSoid(registrationFormSoid);
        //插入检查标识
        relation.setOperatorSoid(operatorSoid);
        //插入服务实例
        if (ObjectUtils.isNotEmpty(serviceInstanceVo.getMsdServiceInstanceSoid())) {
            relation.setMsdServiceInstanceSoid(serviceInstanceVo.getMsdServiceInstanceSoid());
        }
        addDocReportRequisitionRelationCommonInfo(request, employeeSoid, stReportSoid, registrationNo, requestSoid, relationSoid, relation);
        return relation;
    }

    private DocReportRequisitionRelation createDocReportRequisitionRelation(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid,
                                                                            Long requestSoid, String registrationNo, Long examinationVisitSoid,
                                                                            ServiceInstanceVo serviceInstanceVo, Long relationSoid) {
        return createDocReportRequisitionRelation(request, employeeSoid, stReportSoid, request.getRegistrationFormSoid(), registrationNo,
                requestSoid, examinationVisitSoid, serviceInstanceVo, relationSoid);
    }


    private void addDocReportRequisitionRelationCommonInfo(DocReportPreservationRequest request, Long employeeSoid, Long stReportSoid,
                                                           String registrationNo, Long requestSoid, Long relationSoid, DocReportRequisitionRelation relation) {
        relation.setStReportSvcSoid(relationSoid);
        relation.setStReportSoid(stReportSoid);
        relation.setRequestSoid(requestSoid);
        relation.setRegistrationNo(registrationNo);
        relation.setIsDelete(0L);
        Date currentTime = new Date();
        relation.setCreateDate(currentTime);
        relation.setUpdateDate(currentTime);
        relation.setUpdateUser(employeeSoid);
        relation.setExamType(request.getExamType());

    }


    /**
     * @return com.mida.tool.common.result.ListResult<com.mida.bms.report.vo.ReportResult>
     * @Author WXL
     * @Description 根据报告soid查询报告
     * @Date 2021/8/5
     * @Param [stReportSoid]
     **/
    @Override
    public ListResult<ReportResult> getDocReportByStReportSoid(Long stReportSoid) {
        log.info("开始报告回显,回显条件: " + stReportSoid);
        StopWatch stopWatch = StopWatch.createStarted();
        ListResult<ReportResult> result = new ListResult<>();
        if (ObjectUtils.isEmpty(stReportSoid)) {
            log.error("报告soid不能为空");
            buildBadRequestListWarn(result, "报告soid不能为空");
        }
        try {
            if (stReportSoid != null) {
                // 报告存储信息
                DocStructReport docStructReport = docStructReportMapper.selectByPrimaryKey(stReportSoid);
                // 报告完整存储(json)
                DocStructReportJson reportJson = docStructReportJsonMapper.selectByStReportSoid(stReportSoid);
                if (reportJson != null) {
                    // 报告流转状态
                    String reportProcessStatus = null;
                    Long reportStatus = null;
                    if (docStructReport != null) {
                        Long processStatus = docStructReport.getReportProcessStatus();
                        reportStatus = docStructReport.getStatus();
                        if (processStatus != null) {
                            if (processStatus.longValue() == ReportProcessStatus.TO_BE_WRITTEN.code) {
                                // 待书写
                                reportProcessStatus = ReportProcessStatus.TO_BE_WRITTEN.name;
                            }
                            if (processStatus.longValue() == ReportProcessStatus.PRINT_COMPLETED.code) {
                                // 打印完成
                                reportProcessStatus = ReportProcessStatus.PRINT_COMPLETED.name;
                            }
                            if (processStatus.longValue() == ReportProcessStatus.REVIEW_COMPLETED.code) {
                                // 审核完成
                                reportProcessStatus = ReportProcessStatus.REVIEW_COMPLETED.name;
                            }
                            if (processStatus.longValue() == ReportProcessStatus.TO_BE_REVIEWED.code) {
                                // 初写完成待审核
                                reportProcessStatus = ReportProcessStatus.TO_BE_REVIEWED.name;
                            }
                        }
                    }
                    String reportContent = reportJson.getReportContent();
                    String emergencySign = null;
                    Long stTemplateInfoSoid = reportJson.getStTemplateInfoSoid();

                    if (StringUtils.isNotEmpty(reportContent) && stTemplateInfoSoid != null) {
                        // 报告
                        List<DocReportVo> docReportVoList = JSONObject.parseArray(reportContent, DocReportVo.class);
                        ReportResult report = new ReportResult();
                        // 报告模板soid
                        report.setStTemplateInfoSoid(stTemplateInfoSoid);
                        // 报告
                        report.setDocReportVoList(docReportVoList);
                        // 报告流转状态
                        report.setReportProcessStatus(reportProcessStatus);
                        // 报告存储信息soid
                        report.setStReportSoid(stReportSoid);
                        // 报告自身状态
                        report.setReportStatus(reportStatus.toString());
                        // 报告加急状态
                        if (emergencySign != null) {
                            report.setEmergencySign(emergencySign);
                        }
                        buildListSuccess(result, report);
                    }
                }
            }
        } catch (Exception e) {
            log.error("报告回显发送异常", e);
            buildListWarn(result, "报告回显失败");
        } finally {
            stopWatch.stop();
            log.info("本次报告回显耗时: " + stopWatch.getTime() + "ms");
        }
        return result;
    }

    /**
     * 根据报告soid，获取报告信息
     *
     * @param stReportSoid
     * @return
     * @throws Exception
     */
    @Override
    public DocStructReport gainDocReportByStReportSoid(
            Long stReportSoid) throws Exception {
        log.info("开始根据报告soid，获取报告信息: " + stReportSoid);
        StopWatch stopWatch = StopWatch.createStarted();
        DocStructReport docStructReport =
                docStructReportMapper.selectByPrimaryKey(stReportSoid);
        stopWatch.stop();
        log.info("本次报告回显耗时: " + stopWatch.getTime() + "ms");
        return docStructReport;
    }

}
